识别列表中的常用列表并返回列表

时间:2018-01-30 06:58:53

标签: c# list linq

我有一个跟踪列表,我需要遍历列表,看看列表中是否有相同的元素,只返回一个唯一的列表。任何人都可以让我知道以下代码的错误和正确的方法吗?

另外,Linq方式做到了,如果有的话?

预期的解决方案是= {{"a", "b", "c"},{"e", "b", "c" }}

class Program1
{
    static void Main(string[] args)
    {
        List<string>[] stringLists = new List<string>[3]
            {
                new List<string>(){ "a", "b", "c" },
                new List<string>(){ "e", "b", "c" },
                new List<string>(){ "a", "b", "c" }
            };

        List<List<string>> prt = new List<List<string>>();

        /* I DONT UNDERSTAND WHY THIS IS NOT WORKING !!!!!!!!!!!!!!! */
        foreach (var item in stringLists)
        {
            for (int i = 0; i < item.Count; i++)
            {
                if (item == stringLists[i] && (!prt.Contains(item)))
                {
                    prt.Add(item);
                }
            }
        }
    }
}

5 个答案:

答案 0 :(得分:2)

您可以使用自定义 open_constr尝试好的Distinct

IEqualityComparer<T>

...

using System.Linq;

...

public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>> {
  public bool Equals(IEnumerable<T> x, IEnumerable<T> y) {
    return Enumerable.SequenceEqual(x, y);
  }

  //TODO: Suboptimal HashCode implementation
  public int GetHashCode(IEnumerable<T> obj) {
    return obj == null
      ? 0 
      : obj.Count(); 
  }
}

测试:

var stringLists = new List<string>() {
  new List<string> {"a", "b", "c"},
  new List<string> {"e", "b", "c"},
  new List<string> {"a", "b", "c"} 
};

// All you have to do is to put Distinct
var result = stringLists
  .Distinct(new SequenceComparer<string>())
  .ToList(); // If you want materialization

结果:

Console.Write(string.Join(Environment.NewLine, result
  .Select(list => string.Join(", ", list))));

答案 1 :(得分:0)

prt.Contains(item)表达式会将List引用与其元素进行比较,因此确定两个列表是否重复是一个错误的选择。

尝试以下

 var stringLists = new List<string>[3]
 {
    new List<string> {"a", "b", "c"},
    new List<string> {"e", "b", "c"},
    new List<string> {"a", "b", "c"}
 };

 var prt = new List<List<string>>();

 foreach (var item in stringLists)
 {
     if(prt.All(it => it.Count != item.Count || it.Except(item).Any()))
          prt.Add(item);
 }

答案 2 :(得分:0)

你需要在所有列表上做联合,而不是做一个明确的联盟。

像这样,只需遍历列表并将其与最后结果联合起来:

List<string> result = new List<string>();
        foreach (var list in stringLists)
        {
            result = result.Union(list).ToList();

        }
        result = result.Distinct().ToList();

答案 3 :(得分:0)

Dmitry Bychenko的答案是要走的路。

对于您的特殊情况以及不包含,的数据,您可以逃脱:

using System;
using System.Linq;
using System.Collections.Generic;

public class Program1
{
    public static void Main()
    {
        var stringLists = new List<List<string>>{
            new List<string> {"a", "b", "c"}, 
            new List<string> {"e", "b", "c"}, 
            new List<string> {"a", "b", "c"}
        };

        var prt = stringLists
            .Select(l => string.Join(",", l))      // make it a string separated by ,
            .Distinct()                            // distinct it using string.Distinct()
            .Select(l => l.Split(',').ToList());   // split it again at , and make it List

        foreach (var p in prt)
        {
            foreach (var c in p)
                Console.WriteLine(c);

            Console.WriteLine();            
        }   
    }
}

在这种方法中有很多不需要的对象创建 - 但我工作(直到你的数据包含, - 然后会混淆你的列表)。

输出:

a
b
c

e
b
c

答案 4 :(得分:0)

您的误解是您希望声明

true

item中已存在prt中的字符串序列时返回Contains。但是,void Main() { Console.Write( (new []{new []{ "a", "b", "c" }}).Contains(new[] { "a", "b", "c" })); // Prints false } 内部的测试用于确定这是一个引用相等,而不是逐项相等。这是一个最简单的例子来说明这一点:

class Program1
{
    static void Main(string[] args)
    {
        List<string>[] stringLists = new List<string>[3]
            {
                new List<string>(){ "a", "b", "c" },
                new List<string>(){ "e", "b", "c" },
                new List<string>(){ "a", "b", "c" }
            };

        List<List<string>> prt = new List<List<string>>();
        for(int i = 0; i < 3; i++)
        {
            bool isDifferentFromAllOthers = true;
            for(int j = 0; j < i; j++)
            {
                bool isSameAsThisItem = true;
                for(int item = 0; item < 3; item++)
                {
                    // !!! Here is the explicit item by item string comparison
                    if (stringLists[i][item] != stringLists[j][item])
                    {
                        isSameAsThisItem = false;
                        break;
                    }                   
                }
                if (isSameAsThisItem)
                {
                    isDifferentFromAllOthers = false;
                    break;
                }
            }
            if (isDifferentFromAllOthers)
            {
                prt.Add(stringLists[i]);
            }
        }


//        /* I DONT UNDERSTAND WHY THIS IS NOT WORKING !!!!!!!!!!!!!!! */
//        foreach (var item in stringLists)
//        {
//            for (int i = 0; i < item.Count; i++)
//            {
//                if (item == stringLists[i] && (!prt.Contains(item)))
//                {
//                    prt.Add(item);
//                }
//            }
//        }
    }
}

您需要使用深度等于比较器,如@Dmitry的答案,它会创建每个列表的摘要(哈希)并比较摘要,或明确地执行此操作,如下代码:

CREATE TRIGGER trg_newslistusers AFTER INSERT ON lisc_user_usergroup_map
FOR EACH ROW
INSERT IGNORE INTO lisc_acymailing_listsub
SELECT b.group_id, a.subid,UNIX_TIMESTAMP(), NULL, 1  FROM lisc_acymailing_subscriber a INNER JOIN  lisc_user_usergroup_map b ON a.userid = b.user_id;