简体   繁体   English

在C#中,如何识别不同的对,并计算一长对对中它发生了多少次?

[英]In C#, how do I identify distinct pairs and count how many times it occurred in a long list of pairs?

I am using Visual C# 2010 Express. 我正在使用Visual C#2010 Express。 I have an array of students that tells me which pair of students have worked together in the past. 我有一群学生,告诉我过去有一对学生曾一起工作过。 So, arrStudents(0,0) might contain Joe and arrStudents(0,1) contains Bob, and sometimes vice versa. 因此,arrStudents(0,0)可能包含Joe,而arrStudents(0,1)可能包含Bob,有时反之亦然。 The order in which the names are recorded doesn't matter, it's just the pairing information that I care about. 名称的记录顺序无关紧要,只是我关心的配对信息。

Example: 例:

Joe - Bob
Mary - Bob
Bob - Joe
Mary - Joe
Jack - Mary
Joe - Bob

What method should I use to identify all distinct pairs and to count how many times it occurred? 我应该使用什么方法来识别所有不同的对并计算发生了多少次?

So, since (Joe - Bob) and (Bob - Joe) are the same pair the results should yield: 因此,由于(Joe-Bob)和(Bob-Joe)是同一对,因此结果应为:

Joe - Bob, 3
Mary - Bob, 1
Mary - Joe, 1
Jack - Mary, 1

I'd create a Dictionary , where the key is a student-pair and the value is the count. 我将创建一个Dictionary ,其中键是学生对,值是计数。 Then iterate through all the pairs and add them to the dictionary. 然后遍历所有对,并将它们添加到字典中。 For each pair, sort the names alphabetically (or whatever) so that both "Joe-Bob" and "Bob-Joe" end up as "Bob-Joe". 对于每对,请按字母顺序(或其他)对名称进行排序,以使“ Joe-Bob”和“ Bob-Joe”都以“ Bob-Joe”结尾。 If the pair already exists in the dictionary, increment the corressponding value by 1. If it doesn't, add it and set the value to 1. In the end, just iterate through the dictionary and you'll have your results. 如果字典中已经存在该对,则将对应的值增加1。如果不存在,则将其相加并将其值设置为1。最后,只需遍历字典即可得到结果。

List<Tuple<string, string>> list = new List<Tuple<string, string>>()
{
    //Joe - Bob Mary - Bob Bob - Joe Mary - Joe Jack - Mary Joe - Bob
    new Tuple<string,string>("Joe","Bob"),
    new Tuple<string,string>("Mary","Bob"),
    new Tuple<string,string>("Bob","Joe"),
    new Tuple<string,string>("Mary","Joe"),
    new Tuple<string,string>("Jack","Mary"),
    new Tuple<string,string>("Joe","Bob")
};

var result = list.GroupBy(x=>x, new MyComparer())
    .Select(g=>new {Count = g.Count(),Pair = g.First()})
    .ToArray();

-- -

public class MyComparer : IEqualityComparer<Tuple<string, string>>
{
    public bool Equals(Tuple<string, string> x, Tuple<string, string> y)
    {
        return (x.Item1 == y.Item1 && x.Item2 == y.Item2) ||
            (x.Item2 == y.Item1 && x.Item1 == y.Item2);
    }

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

Easiest way I can think of is a little Linq. 我能想到的最简单的方法是使用一点Linq。 First, get all the pairs of students as a list of pairs of strings, similar to what you show. 首先,将所有成对的学生作为成对的字符串列表获得,与您显示的类似。 A List<Tuple<string, string>> should work. 一个List<Tuple<string, string>>应该可以工作。 The tricky bit is that you're using a rectangular array, which has some weird access behavior if you treat it as an IEnumerable. 棘手的一点是,您使用的是矩形数组,如果将其视为IEnumerable,则具有一些奇怪的访问行为。

Then, you need a way to compare two pairs for equality. 然后,您需要一种比较两个对是否相等的方法。 I have a generic class that allows you to specify a lambda statement to use for the comparison, so you don't have to implement a single-purpose IEqualityComparer for each custom comparison: 我有一个通用类,可让您指定用于比较的lambda语句,因此您不必为每个自定义比较实现单一用途的IEqualityComparer:

public class GenericEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> equalityComparer;
    private readonly Func<T, int> hashFunc;

    public GenericEqualityComparer(Func<T, T, bool> compareFunc, Func<T,int> hashFunc)
        :this(compareFunc)
    {
        this.equalityComparer = compareFunc;
        this.hashFunc = hashFunc;
    }

    public GenericEqualityComparer(Func<T, T, bool> compareFunc)
    {
        this.equalityComparer = compareFunc;
        this.hashFunc = o => o.GetHashCode();
    }

    public bool Equals(T x, T y)
    {
        return equalityComparer(x, y);
    }

    public int GetHashCode(T obj)
    {
        return hashFunc(obj);
    }
}

Then, you simply run the List of values through Linq's GroupBy() method, specifying the GenericEqualityComparer to compare the values in your custom order-independent way: 然后,您只需通过Linq的GroupBy()方法运行值列表,指定GenericEqualityComparer即可以自定义顺序无关的方式比较值:

var pairCounts = pairList
                    .GroupBy(p=>p, //key selector; we want the Tuple itself
                       new GenericEqualityComparer<Tuple<string,string>>(
                          (a,b)=>(a.Item1 == b.Item1 && a.Item2 == b.Item2) 
                             || (a.Item1 == b.Item2 && a.Item2 == b.Item1))
                    .Select(g=>new Tuple<string, int>(g.Key.Item1 + " - " + g.Key.Item2,
                                                      g.Count());

The end result will be a List<Tuple<string,int>> containing the first permutation of each pair of names found, and how many either permutation of that pair was found in the list. 最终结果将是一个List<Tuple<string,int>>其中包含找到的每对名称的第一个排列,以及在列表中找到该对的多少个排列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM