在两个数组C#中查找唯一字符串

时间:2012-08-22 13:16:05

标签: c# arrays string datagridview unique

您好我正在尝试在从XML文件填充的两个dataGridView表中查找唯一字符串。我所做的代码运行没有问题,但它无法检测我何时在其中一个表中更改字符串(使其唯一)。我的逻辑有什么问题吗?

    private void button5_Click(object sender, EventArgs e)
    {
        string[] column1 = new string[dataGridView1.Rows.Count];
        string[] column2 = new string[dataGridView2.Rows.Count];
        int unique = 0;
        bool found = false;
        for (int i = 0; i < dataGridView1.Rows.Count; i++)
        {
            column1[i] = Convert.ToString(dataGridView1.Rows[i].Cells[2].Value);
        }
        for (int i = 0; i < dataGridView2.Rows.Count; i++)
        {
            column2[i] = Convert.ToString(dataGridView2.Rows[i].Cells[2].Value);
        }
        for (int i = 0; i < column1.Length; i++)
        {
            for (int j = 0; j < column2.Length; j++)
            {
                if (column1[i] == column2[j])
                {
                    found = true;
                }
            }
            if (found == false)
            {
                unique++;
                found = false;
            }
        }
        MessageBox.Show(unique + " unique strings found!"); 
    }

最终解决方案需要能够返回包含唯一字符串的单元格,以便我可以向用户突出显示它们。非常感谢你的帮助!

5 个答案:

答案 0 :(得分:3)

简单使用linq:

array1.Except(array2).Concat(array2.Except(array1))

在回复您的注释时,您可以使用两个左连接模拟完整的外连接,并在输出中查找空值。在另一侧不匹配的连接的任何一侧都可以被认为是唯一的。使用以下扩展名进行连接:

public static class LinqEx
{
    public static IEnumerable<TResult> 
        LeftOuterJoin<TOuter, TInner, TKey, TResult>(
            this IEnumerable<TOuter> outer, 
            IEnumerable<TInner> inner, 
            Func<TOuter, TKey> outerKeySelector, 
            Func<TInner, TKey> innerKeySelector, 
            Func<TOuter, TInner, TResult> resultSelector)
    {
        return outer
            .GroupJoin(
                inner, 
                outerKeySelector, 
                innerKeySelector, 
                (a, b) => new
                {
                    a,
                    b
                })
            .SelectMany(
                x => x.b.DefaultIfEmpty(), 
                (x, b) => resultSelector(x.a, b));
    }

    public static IEnumerable<TResult> 
        FullOuterJoin<TSet1, TSet2, TKey, TResult>(
            this IEnumerable<TSet1> set1, 
            IEnumerable<TSet2> set2, 
            Func<TSet1, TKey> set1Selector, 
            Func<TSet2, TKey> set2Selector, 
            Func<TSet1, TSet2, TResult> resultSelector)
    {
        var leftJoin = set1.
            LeftOuterJoin(
                set2, 
                set1Selector, 
                set2Selector, 
                (s1, s2) => new {s1, s2});
        var rightJoin = set2
            .LeftOuterJoin(
                set1, 
                set2Selector, 
                set1Selector, 
                (s2, s1) => new {s1, s2});
        return leftJoin.Union(rightJoin)
            .Select(x => resultSelector(x.s1, x.s2));

    }
}
然后,您可以创建捕获附加数据的匿名对象,例如项目的索引及其来源,以及外部连接。连接两侧的项目结果将被过滤掉(因为它们存在于两个集合中),因此结果集现在只包含其中一个集合唯一的项目。

void Main()
{
    var set1 = new[] {"a", "b", "c"};
    var set2 = new[] {"b", "c", "d", "d"};
    var annotatedSet1 = set1
        .Select((item,index) => new {src = "set1", index, item});
    var annotatedSet2 = set2
        .Select((item,index) => new {src = "set2", index, item});

    var uniques = annotatedSet1
        .FullOuterJoin(
            annotatedSet2, 
            x => x.item, 
            x => x.item,
            (s1, s2) => new {s1, s2})
        .Where(x => x.s1 == null || x.s2 == null)
        .Select(x => x.s1 ?? x.s2);
}

会产生结果:

{src="set1", index=0, item="a"}
{src="set2", index=2, item="d"}
{src="set2", index=3, item="d"}

答案 1 :(得分:0)

您可以使用链接运算符,Union和Distinct运算符

var temp =  column1.Union(column2);
var result   = temp.Distinct();

答案 2 :(得分:0)

这是Linq与Enumerable.Except

的方式
var dg1Cell2 = dataGridView1
    .Rows.Cast<DataGridViewRow>()
    .Select(r => r.Cells[2].Value.ToString());
var dg2Cell2 = dataGridView1
    .Rows.Cast<DataGridViewRow>()
    .Select(r => r.Cells[2].Value.ToString());
var uniqueInDG1 = dg1Cell2.Except(dg2Cell2);
var result = from r in dataGridView1.Rows.Cast<DataGridViewRow>()
             join u in uniqueInDG1 on r.Cells[2].Value.ToString() equals u
             select r;

Except产生一组差异,因此只保留第一个序列中的唯一字符串。然后我将结果加入DataGridViewRows

它比看起来效率更高,因为它全部是懒惰地执行,除了在内部使用set并且linq-to-objects中的join也是very efficient

答案 3 :(得分:0)

感谢您的所有回复,但简单的回答是我没有在正确的点重置找到的值为false。我很欣赏您的解决方案所付出的努力,但它们对我的知识水平来说太复杂了。

以下是经过调整的代码:

    private void button5_Click(object sender, EventArgs e)
    {
        string[] column1 = new string[dataGridView1.Rows.Count];
        string[] column2 = new string[dataGridView2.Rows.Count];
        int unique = 0;
        bool found = false;
        for (int i = 0; i < dataGridView1.Rows.Count; i++)
        {
            column1[i] = Convert.ToString(dataGridView1.Rows[i].Cells[2].Value);
        }
        for (int i = 0; i < dataGridView2.Rows.Count; i++)
        {
            column2[i] = Convert.ToString(dataGridView2.Rows[i].Cells[2].Value);
        }
        for (int i = 0; i < column1.Length; i++)
        {
            for (int j = 0; j < column2.Length; j++)
            {
                if (column1[i] == column2[j])
                {
                    found = true;
                }
            }
            if (found == false)
            {
                unique++;
            }
            found = false;
        }
        MessageBox.Show(unique + " unique strings found!");         
    }

答案 4 :(得分:0)

以下代码将从 2 个字符串数组中返回不同的字符串数组

public string[] UniqueNames(string[] names1, string[] names2) {
    newName = names1.ToList();
    foreach (var dr in names2) {
        if (!newName.Contains(dr)) {
            newName.Add(dr);
        }
    }
    string[] newNameArray = newName.ToArray();
    return newNameArray;
}

或者你也可以试试,

public string[] UniqueNames(string[] names1, string[] names2) {            
    return names1.Union(names2).ToArray(); ;            
}