使用LINQ比较两个数组

时间:2015-11-19 19:04:49

标签: c# .net arrays linq compare

例如,我有两个数组:

string[] arrayOne = {"One", "Two", "Three", "Three", "Three"};
string[] arrayTwo = {"One", "Two", "Three"};

var result = arrayOne.Except(arrayTwo);

foreach (string s in result) Console.WriteLine(s);

我想要来自arrayOne的{​​{1}}中没有的项目。所以我需要结果为: arrayTwo 但是因为它治疗"三"一般而不检查其他两项("三","三")。

我不想写一个巨大的方法来解决这个问题。在SO上尝试了其他的答案,但没有按预期工作:(。

感谢!!!

8 个答案:

答案 0 :(得分:5)

构建第二个HashSet,然后过滤第一个只允许项目,如果你不能从HashSet中删除项目。

int temp = _day;
_day = _day + 1;
_day = temp;

<击>

考虑到评论中的额外要求,var hs = new HashSet<string>(arrayTwo); var filtered = arrayOne.Where(item => !hs.Remove(item)).ToArray(); 的一些漂亮用法在这里很有效。

ILookup

答案 1 :(得分:3)

答案取决于数组大小,重复元素数,代码速度的重要性。

对于小型数组,以下代码将是最简单和最好的:

List<string> result = new List<string>(arrayOne);
foreach (string element in arrayTwo)
    result.Remove(element);

如果你想要更大的数组效率,你可以使用消费者的答案。

如果您想要最有效的代码,则必须手动编码以下算法: 1.对arrayOne和arrayTwo进行排序。 2.同时迭代两种算法(如在mergesort中)并省略具有相同元素的对。

Proc:没有沉重的Lookup对象 缺点:需要编码

答案 2 :(得分:2)

这样做的一种方法是包括索引以及:

var result = arrayOne.Select((r, i) => new {Value = r, Index = i})
    .Except(arrayTwo.Select((r, i) => new {Value = r, Index = i}))
    .Select(t => t.Value);

这将为您输入所需的输出,但上述方法的问题是,不同索引上的相同字符串将被区别对待。

忽略指数的另一种方法可以像:

string[] arrayOne = { "One", "Two", "Three", "Three", "Three", "X" };
string[] arrayTwo = { "One", "Two", "Three" };

var query1 = arrayOne.GroupBy(r => r)
    .Select(grp => new
    {
        Value = grp.Key,
        Count = grp.Count(),
    });

var query2 = arrayTwo.GroupBy(r => r)
    .Select(grp => new
    {
        Value = grp.Key,
        Count = grp.Count(),

    });

var result = query1.Select(r => r.Value).Except(query2.Select(r => r.Value)).ToList();
var matchedButdiffferentCount = from r1 in query1
    join r2 in query2 on r1.Value equals r2.Value
    where r1.Count > r2.Count
    select Enumerable.Repeat(r1.Value, r1.Count - r2.Count);

result.AddRange(matchedButdiffferentCount.SelectMany(r=> r));

result将包含{"X", "Three", "Three"}

答案 3 :(得分:2)

您可以通过向数组的每个元素添加索引来获得所需的输出,使其看起来像

{{ "One", 0 }, { "Two", 0 }, { "Three", 0 }, { "Three", 1 }, { "Three", 2 }}
{{ "One", 0 }, { "Two", 0 }, { "Three", 0 }}

然后您可以使用Except删除重复项

var arrayOneWithIndex = arrayOne
    .GroupBy(x => x)
    .SelectMany(g => g.Select((e, i) => new { Value = e, Index = i }));

var arrayTwoWithIndex = arrayTwo
    .GroupBy(x => x)
    .SelectMany(g => g.Select((e, i) => new { Value = e, Index = i }));

var result = arrayOneWithIndex.Except(arrayTwoWithIndex).Select(x => x.Value);

答案 4 :(得分:1)

由于不需要最终输出的顺序,您可以在arrayOne中对重复的字符串进行分组,并在arrayTwo中分组减去计数(和当前)重复次数。然后,您可以再次展开集合,同时使用Enumerable.Repeat复制迭代次数。

string[] arrayOne = {"One", "Two", "Three", "Three", "Three"};
string[] arrayTwo = {"One", "Two", "Three"};

var groupedTwo = arrayTwo
    .GroupBy(g => g)
    .ToDictionary(g => g.Key, g => g.Count());

var groupedResult = arrayOne
    .GroupBy(a => a)
    .Select(g => new {g.Key, Count = g.Count()})
    .Select(g => new {g.Key, Residual = g.Count - 
       (groupedTwo.ContainsKey(g.Key) ? groupedTwo[g.Key] : 0)})
    .SelectMany(g => Enumerable.Repeat(g.Key, g.Residual));

foreach (string s in groupedResult) 
{
   Console.WriteLine(s);
}

请注意,这显然不会保留原始顺序中可能发生的任何交错。

e.g。对于

string[] arrayOne = {"Three", "Four", "One", "Two", "Three", "Three"};

答案非直观地

Three
Three
Four

答案 5 :(得分:1)

迟到这个讨论,并在此处记录以供参考。 LINQ的Except方法使用默认的相等比较器来确定两个数组中哪些项匹配。在这种情况下,默认的相等比较器调用对象上的Equals方法。对于字符串,此方法已被重载以比较字符串的内容,而不是其标识(引用)。

这解释了为什么在这种特定情况下会发生这种情况。当然,它没有提供解决方案,但我相信其他人已经提供了出色的答案。 (实际上,这比评论更适合我。)

我可能提出的一个建议是编写自定义比较器,并将其传递给接受一个的Except重载。自定义比较器并不过分复杂,但考虑到您的场景,我了解您可能不希望这样做的地方。

答案 6 :(得分:0)

试试这个:

actions: {
  submitForm() {
    var inpObj = this.get('name');
    if(!inpObj.checkValidity()) {
      // error handling
      alert('ok');
    } else {
      // save your data, or whatever you need to do
      this.transitionTo('some.route');
    }
  }
}

<击> 好的,如果这不起作用 - 我会更仔细地阅读评论。

以下代码:

var result = from s in first
            where !string.IsNullOrWhiteSpace(s) &&
            !second.Contains(s)
             select s;

产生以下结果:

private static void Main(string[] args)
    {

        string[] first = {"One", "Two", "Three", "Three", "Three"};
        string[] second = {"One", "Two", "Four", "Three"};

        var result = FirstExceptSecond(first, second);

        foreach (string s in result)
        {
            Console.WriteLine(s);
        }
    }

    private static IEnumerable<string> FirstExceptSecond(IList<string> first, IList<string> second)
    {
        List<string> firstList = new List<string>(first);
        List<string> secondList = second as List<string> ?? second.ToList();

        foreach (string s in secondList)
        {
            if (firstList.Contains(s))
            {
                firstList.Remove(s);
            }
        }

        return firstList;
    } 

答案 7 :(得分:0)

使用LINQ比较数组相等性的另一种方法如下。

LINQ中使用的逻辑: 在这段代码中,我正在过滤第一个数组元素,以使第一个数组中的每个元素都等于第二个数组中的对应元素,并且第一个数组的当前索引存在于第二个数组中;如果要比较的两个数组相等,则此过滤将导致元素数量与第一个数组中的元素数量相同。

string[] arrayOne = {"One", "Two", "Three", "Three", "Three"};
string[] arrayTwo = {"One", "Two", "Three"};

bool result =(arrayOne.Where((string n, int i) => i <= (arrayTwo.Length-1) &&
                                           n == arrayTwo[i]).Count() == arrayOne.Length);

 //if result == true then arrays are equal else they are not