簡體   English   中英

從元組列表中刪除重復項

[英]Removing duplicates from a list of tuples

我有一個Tuple<string,string>對象列表,我想刪除重復項,例如,元組(a,b)(b,a)被認為是相同的(這些是圖的邊緣)。 什么是這樣做的方法?

您需要創建一個比較器,它可以比較元組,使得項目的順序無關緊要:

public class UnorderedTupleComparer<T> : IEqualityComparer<Tuple<T, T>>
{
    private IEqualityComparer<T> comparer;
    public UnorderedTupleComparer(IEqualityComparer<T> comparer = null)
    {
        this.comparer = comparer ?? EqualityComparer<T>.Default;
    }

    public bool Equals(Tuple<T, T> x, Tuple<T, T> y)
    {
        return comparer.Equals(x.Item1, y.Item1) && comparer.Equals(x.Item2, y.Item2) ||
                comparer.Equals(x.Item1, y.Item2) && comparer.Equals(x.Item2, y.Item1);
    }

    public int GetHashCode(Tuple<T, T> obj)
    {
        return comparer.GetHashCode(obj.Item1) ^ comparer.GetHashCode(obj.Item2);
    }
}

請注意,哈希碼的異或運算是一種無論操作數的順序如何都會產生相同結果的操作,這使得它在這里是可取的(但在大多數哈希碼生成算法中不是,因為它通常是一個不受歡迎的屬性)。 至於Equals ,只需檢查兩個可能的配對。

一旦你有了,你可以這樣做:

var query = data.Distinct(new UnorderedTupleComparer<string>());

您可能需要創建一個實現IEqualityComparer<Tuple<string, string>>的類:

public class TupleComparer : IEqualityComparer<Tuple<string, string>>
{
    public bool Equals(Tuple<string, string> x, Tuple<string, string> y)
    {

        if (ReferenceEquals(x, y))
        {
            return true;
        }

        if (ReferenceEquals(x, null) || ReferenceEquals(y, null))
        {
            return false;
        }

        if (x.Item1.Equals(y.Item2) && x.Item2.Equals(y.Item1))
        {
            return true;
        }

        return x.Item1.Equals(y.Item1) && x.Item2.Equals(y.Item2);
    }   

    public int GetHashCode(Tuple<string, string> tuple)
    {
        // implementation
    }
}

然后,您可以像這樣使用Distinct() LINQ 方法:

List<Tuple<string, string>> list = new List<Tuple<string, string>> { Tuple.Create("a", "b"), Tuple.Create("a", "c"), Tuple.Create("b", "a") };
var result = list.Distinct(new TupleComparer());

嘗試使用字典並組成一個表示每個元組的鍵。 你有一個不會出現在你的字符串中的字符,你可以用作分隔符嗎? 我在這個例子中選擇了“:”:

static void Main(string[] args)
{
    // original list of data
    var list = new List<Tuple<string, string>> { };
    list.Add(new Tuple<string, string>("a", "b"));
    list.Add(new Tuple<string, string>("b", "a"));

    // dictionary to hold unique tuples
    var dict = new Dictionary<string, Tuple<string, string>>();
    foreach (var item in list)
    {
        var key1 = string.Concat(item.Item1, ":", item.Item2);
        var key2 = string.Concat(item.Item2, ":", item.Item1);

        // if dict doesnt contain tuple, add it.
        if (!dict.ContainsKey(key1) && !dict.ContainsKey(key2))
            dict.Add(key1, item);
    }

    // print unique tuples
    foreach (var item in dict)
    {
        var tuple = item.Value;
        Console.WriteLine(string.Concat(tuple.Item1, ":", tuple.Item2));
    }

    Console.ReadKey();
}

要保留原始元素,請使用group by而不是Distinct ,這樣我們仍然可以訪問組的第一個元素:

實時代碼: https ://dotnetfiddle.net/LYZItb

using System;
using System.Collections.Generic;

using System.Linq;

public class Program
{
    static List<Tuple<string, string>> myList = new List<Tuple<string, string>>()
    {
        Tuple.Create<string, string>("B", "A"),
        Tuple.Create<string, string>("A", "B"), // duplicate
        Tuple.Create<string, string>("C", "B"),
        Tuple.Create<string, string>("C", "B"), // duplicate
        Tuple.Create<string, string>("A", "D"),
        Tuple.Create<string, string>("E", "F"),
        Tuple.Create<string, string>("F", "E"), // duplicate        
    };

    public static void Main()
    {

        var result =
            from y in 
                from x in myList
                select new { Original = x, SortedPair = new[] { x.Item1, x.Item2 }.OrderBy(s => s).ToArray() }  
                group y by new { NormalizedTuple = Tuple.Create<string,string>(y.SortedPair[0], y.SortedPair[1]) } into grp
            select new { Pair = grp.Key.NormalizedTuple, Original = grp.First().Original };


        foreach(var item in result)
        {
            Console.WriteLine("Pair: {0} {1}", item.Original.Item1, item.Original.Item2);
        }
    }
}

輸出:

Pair: B A
Pair: C B
Pair: A D
Pair: E F

實時代碼: https ://dotnetfiddle.net/LUErFj

首先對 Tuple 對進行排序,然后執行 Distinct:

using System;
using System.Collections.Generic;

using System.Linq;

public class Program
{
    static List<Tuple<string, string>> myList = new List<Tuple<string, string>>()
    {
        Tuple.Create<string, string>("A", "B"),
        Tuple.Create<string, string>("B", "A"), // duplicate
        Tuple.Create<string, string>("C", "B"),
        Tuple.Create<string, string>("C", "B"), // duplicate
        Tuple.Create<string, string>("A", "D")              
    };

    public static void Main()
    {
        myList
            .Select(x => new[] { x.Item1, x.Item2 }.OrderBy(s => s).ToArray())
            .Select(x => Tuple.Create<string,string>(x[0], x[1]))
            .Distinct()
            .Dump();
    }
}

輸出:

Dumping object(System.Linq.<DistinctIterator>d__81`1[Tuple`2[String,String]])
[
   {
   Item1  : A
   Item2  : B
   ToString(): (A, B)
   },
   {
   Item1  : B
   Item2  : C
   ToString(): (B, C)
   },
   {
   Item1  : A
   Item2  : D
   ToString(): (A, D)
   }
]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM