首页 > 解决方案 > 使用 C# 在复杂的 JSON 数组中查找和打印重复项

问题描述

我试图在 .NET 中使用 C# 从复杂的嵌套 JSON 数组中找出并打印重复项。

我想检查值“title”是否重复,并且还有一个嵌套的 JSON 数组(项目),其中包含以下值:我要检查重复项的标题值。

因此,嵌套数组的值:标题应与其他嵌套数组值的值进行比较。外部“标题”应与外部“标题”核对。

id 和 sourceId 应该被忽略

尝试使用 foreach 执行此操作,但无法使用 . (点)。然后尝试使用 for 循环,但我迷路了。

结果,我想打印重复的值。

你可以帮帮我吗?

JSON数组的外观概述如下

{
    "id": "0789a960-45de-11ea-ae56-23ecd3bd0e35",
    "sourceId": "6e009cc0-fc83-11e9-8fb9-01af70ec8d3f",
    "title": "Glass-reinforced concrete (GRC) built-in quoins",
    "items": [{
        "title": "Description",
        "value": ""
    }, {
        "title": "Manufacturer",
        "value": ""
    }, {
        "title": "Height (overall)",
        "value": ""
    }, {
        "title": "Applied surface finish",
        "value": ""
    }, {
        "title": "Applied finish colour",
        "value": ""
    }]
}, {
    "id": "0a607010-45de-11ea-ae56-23ecd3bd0e35",
    "sourceId": "73a96f31-fc83-11e9-8fb9-01af70ec8d3f",
    "title": "Clay bricks",
    "items": [{
        "title": "Description",
        "value": ""
    }, {
        "title": "Manufacturer",
        "value": ""
    }, {
        "title": "Standard",
        "value": ""
    }, {
        "title": "Brick description",
        "value": ""
    }, {
        "title": "Execution",
        "value": ""
    }]
}, {
    "id": "0ce40db0-45de-11ea-ae56-23ecd3bd0e35",
    "sourceId": "73a96f31-fc83-11e9-8fb9-01af70ec8d3f",
    "title": "Clay bricks",
    "items": [{
        "title": "Description",
        "value": ""
    }, {
        "title": "Manufacturer",
        "value": ""
    }, {
        "title": "Standard",
        "value": ""
    }, {
        "title": "Appearance",
        "value": ""
    }, {
        "title": "Execution",
        "value": ""
    }]
},  ............. and so on

标签: c#arraysjson.netfor-loop

解决方案


一种方法是将上述 JSON 转换为 C# 对象以保存您要反序列化的属性,例如:

public class Thing
{
    public string Title { get; set; }
    public List<TitleValue> Items { get; set; }
}

public class TitleValue
{
    public string Title { get; set; }
    public string Value { get; set; }

    // This is needed later for the comparer
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 31 + Title.GetHashCode();
            hash = hash * 31 + Value.GetHashCode();
            return hash;
        }
    }
}

现在您可以反序列化成这样的项目列表:

// If you are using Newtonsoft JSON.Net:
var things = JsonConvert.DeserializeObject<List<Thing>>(jsonString);

// If you are using System.Text.Json:

var settings = new System.Text.Json.JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};

var things = JsonSerializer.Deserialize<List<Thing>>(jsonString, settings);

您可以制作的下一件事是实现IEqualityComparer<Thing>您可以传递给 Linq的类GroupBy。例如:

public class ThingEqualityComparer : IEqualityComparer<Thing>
{
    public bool Equals(Thing x, Thing y)
    {
        if (!x.Title.Equals(y.Title))
            return false;

        if (x.Items.Count() != y.Items.Count())
            return false;

        foreach (var item in x.Items)
        {
            if (!y.Items.Any(otherItem => otherItem.Title.Equals(item.Title) && 
                                          otherItem.Value.Equals(item.Value)))
                return false;
        }

        return true;
    }

    public int GetHashCode(Thing obj)
    {
        unchecked
        {
            int hash = 17;
            hash = hash * 31 + obj.Title.GetHashCode();
            foreach (var item in obj.Items)
            {
                hash = hash * 31 + item.GetHashCode();
            }
            return hash;
        }
    }
}

现在您可以运行一些 Linq 查询,例如:

var thingCounts = things
    .GroupBy(t => t, new ThingEqualityComparer())
    .Select(g => new 
    {
        Thing = g.Key, 
        Count = g.Count() 
    });

如果您想在该列表中查找重复项,可以使用Where子句过滤它们:

var duplicateThingCounts = thingCounts.Where(tc => tc.Count > 1)

现在您可以对重复项做任何您想做的事情,例如打印出您喜欢的任何内容:

foreach (var thingCount in duplicateThingCounts)
{
    Console.WriteLine(thingCount.Thing.Title);
}

推荐阅读