在对象列表中搜索重复键,并将字符串值放入字符串数组中

时间:2013-05-31 18:37:50

标签: c# linq duplicates

我想要做的是在searchValues列表中搜索重复的itemId,当我找到它们时,将单个字符串值放入字符串值数组中。

SearchValue对象:

public class SearchValue<TItemId>
{
    public TItemId ItemId { get; set; }
    public string Value { get; set; }
    public string[] Values { get; set; }
}

init之后的测试搜索值如下所示:

   searchValues[0]
        .ItemId == 16
        .Value == "2"
    searchValues[1]
        .ItemId == 16
        .Value == "3"
    searchValues[2]
        .ItemId == 15
        .Value == "6"
    searchValues[3]
        .ItemId == 15
        .Value == "3"
    searchValues[4]
        .ItemId == 5
        .Value == "Vertonghen"

我希望我的最终结果如下:

searchValues[0]
    .ItemId == 16
    .Values == "2,3"
searchValues[1]
    .ItemId == 15
    .Values == "6,3"
searchValues[2]
    .ItemId == 5
    .Value == "Vertonghen"

我真的想用LINQ做这件事。我已设法创建另一个SearchValue列表:

List<SearchValue<Byte>> duplicateSearchItems = (from x in searchValues
                                 group x by x.ItemId into grps
                                 orderby grps.Key
                                 where grps.Count() > 1
                                 select grps).SelectMany(group => group).ToList();

...但是将值放入values数组会给我带来麻烦。理想情况下,如果LINQ可以返回一个包含重复记录的单个列表,这些重复记录被转换为数组,其中非重复项完好无损。可能是某种嵌套查询?我很难过。有什么想法吗?

提前致谢!

4 个答案:

答案 0 :(得分:0)

为什么不使用词典

    Dictionary<int,string> d = new Dictionary<int,string>();
    foreach(var x in searchValues)
    {
        if(d.ContainsKey(x.ItemId))
           d[x.ItemId] = string.Format("{0},{1}",d[x.ItemId],x.Value);
        else
           d.Add(x.ItemId,x.Value);
    }

最后简单地通过词典重复

    foreach(var entry in d)
    {
       ConsoleWriteline(entry.Key+" : "+entry.Value);
    }

答案 1 :(得分:0)

单独使用Linq不能用于修改原始列表或修改列表中的项目。但是,您可以执行此操作以创建新列表:

List<SearchValue<Byte>> results = 
    (from x in searchValues
     group x by x.ItemId into g
     select new SearchValue<Byte>()
     {
         ItemId = g.Key,
         Value = g.Value.First().Value,
         Values = g.Value.Select(i => i.Value).ToArray(),
     }
    .ToList();

或者用流利的语法:

List<SearchValue<Byte>> results = searchValues
    .GroupBy(x => x.ItemId)
    .Select(g => new SearchValue<Byte>()
            {
                ItemId = g.Key,
                Value = g.Value.First().Value,
                Values = g.Value.Select(i => i.Value).ToArray(),
            })
   .ToList();

但是,根据您的具体情况,ILookup可能更适合您:

var results = searchValues.ToLookup(x => x.ItemId, x => x.Value);
Console.Write(String.Join(", ", results[16])); // 2, 16

答案 2 :(得分:0)

我认为LINQ不会为您提供最佳解决方案。与尼古拉相似,我会使用字典。如果您未与SearchValue数据类型结合,则可以避免将数据推回到您的类型中的第二个循环。字典&gt;会在这里工作。

            var searchValues = new List<SearchValue<int>>();
            var distinctItemIds = new Dictionary<int, List<string>>();

            foreach (var item in searchValues)
            {
                if (!distinctItemIds.ContainsKey(item.ItemId))
                {
                    distinctItemIds.Add(item.ItemId, new List<string>());
                }

                // Add the value
                distinctItemIds[item.ItemId].Add(item.Value);
            }

            // Put values back into your data object
            var finishedValues = new List<SearchValue<int>>();

            foreach (var keyValuePair in distinctItemIds)
            {
                finishedValues.Add(new SearchValue<int>()
                {
                    ItemId = keyValuePair.Key,
                    Values = keyValuePair.Value.ToArray()
                });
            }

答案 3 :(得分:0)

我设法使用LINQ解决了这个问题。

// Get a new list of unique items to add our duplicated items to
List<SearchValue<Byte>> finalSearchItems = (from x in searchValues
                            group x by x.ItemId into grps
                            orderby grps.Key
                            where grps.Count() == 1
                            select grps).SelectMany(group => group).ToList();

byte[] duplicateIds = (from x in searchValues
             group x by x.ItemId into grps
             where grps.Count() > 1
             select grps.Key).ToArray();

// Smash the string 'Value' into 'Values[]'
foreach (byte id in duplicateIds)
{
    SearchValue<Byte> val = new SearchValue<byte>();
    val.ItemId = id;
    // Smash
    val.Values = (from s in searchValues
              where s.ItemId == id
              select s.Value).ToArray();
    finalSearchItems.Add(val);
}