0

我正在使用 Visual C# 2010 Express。我有一群学生告诉我过去有哪对学生一起工作过。因此,arrStudents(0,0) 可能包含 Joe,而 arrStudents(0,1) 包含 Bob,有时反之亦然。记录名字的顺序无关紧要,我关心的只是配对信息。

例子:

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

我应该使用什么方法来识别所有不同的对并计算它发生了多少次?

因此,由于 (Joe - Bob) 和 (Bob - Joe) 是同一对,结果应该产生:

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

3 回答 3

6

我会创建一个Dictionary,其中键是学生对,值是计数。然后遍历所有对并将它们添加到字典中。对于每一对,按字母顺序(或其他)对名称进行排序,以使“Joe-Bob”和“Bob-Joe”都以“Bob-Joe”结尾。如果字典中已经存在该对,则将对应的值加 1。如果不存在,则添加它并将值设置为 1。最后,只需遍历字典即可获得结果。

于 2012-09-05T19:07:53.773 回答
4
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();
    }
}
于 2012-09-05T19:10:25.403 回答
0

我能想到的最简单的方法是使用一点 Linq。首先,将所有学生对作为字符串对列表,类似于您显示的内容。AList<Tuple<string, string>>应该工作。棘手的一点是您使用的是矩形数组,如果您将其视为 IEnumerable,它会有一些奇怪的访问行为。

然后,您需要一种方法来比较两对是否相等。我有一个通用类,允许您指定用于比较的 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);
    }
}

然后,您只需通过 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());

最终结果将是List<Tuple<string,int>>包含找到的每对名称的第一个排列,以及在列表中找到该对的任意排列的数量。

于 2012-09-05T19:16:48.823 回答