2

我希望有人能够帮助我,至少对我来说,这是一个相当棘手的算法。

问题

我有一个 List ( 1 <= size <= 5,但直到运行时大小未知) List ( 1 <= size <= 2) 需要组合。这是我正在查看的示例:-

ListOfLists = { {1}, {2,3}, {2,3}, {4}, {2,3} }

所以,我需要做的有两个阶段:-

(1)。我需要以这样一种方式组合内部列表,即任何组合在每个列表中都只有一个项目,也就是说,这里结果集中的可能组合是:-

  • 1,2,2,4,2
  • 1,2,2,4,3
  • 1,2,3,4,2
  • 1,2,3,4,3
  • 1,3,2,4,2
  • 1,3,2,4,3
  • 1,3,3,4,2
  • 1,3,3,4,3

笛卡尔积会处理这个问题,所以第 1 阶段已经完成......现在,我想不通的转折出现了 - 至少我想不出 LINQ 的方法(我仍然一个 LINQ 菜鸟)。

(2)。我现在需要从这个笛卡尔积中过滤掉任何重复的结果。在这种情况下,重复构成结果集中的任何行,每个不同列表元素的数量与另一行相同,即,

1,2,2,4,3 与 1,3,2,4,2 “相同”

因为第一个列表中的每个不同项目在两个列表中出现的次数相同(1 在每个列表中出现一次,2 在每个列表中出现两次,...

因此,最终结果集应如下所示...

  • 1,2,2,4,2
  • 1,2,2,4,3
  • --
  • 1,2,3,4,3
  • --
  • --
  • --
  • 1,3,3,4,3

另一个例子是最坏的情况(从组合的角度来看)ListOfLists 是 {{2,3}, {2,3}, {2,3}, {2,3}, {2,3} },即包含最大大小的内部列表的列表 - 在这种情况下,笛卡尔积结果集中显然会有 32 个结果,但我试图得到的修剪结果集只是: -

  • 2,2,2,2,2
  • 2,2,2,2,3 <-- 所有其他带有四个 2 和一个 3(以任何顺序)的结果都被抑制
  • 2,2,2,3,3 <-- 三个 2 和两个 3 的所有其他结果都被抑制,等等
  • 2,2,3,3,3
  • 2,3,3,3,3
  • 3,3,3,3,3

对于任何有数学头脑的人-我希望你能提供帮助。实际上,我已经为第 2 部分找到了一个可行的解决方案,但它完全是 hack,并且计算量很大,我正在寻找指导以找到更优雅、更有效的 LINQ 解决方案来解决修剪问题。

谢谢阅读。

点子

到目前为止使用的一些资源(获取笛卡尔积)

更新 - 解决方案

抱歉没有早点发布……见下文

4

3 回答 3

3

您应该实现自己的IEqualityComparer<IEnumerable<int>>,然后在Distinct().

中哈希码的选择IEqualityComparer取决于您的实际数据,但如果您的实际数据与示例中的数据相似,我认为这样的内容应该足够了:

class UnorderedQeuenceComparer : IEqualityComparer<IEnumerable<int>>
{
    public bool Equals(IEnumerable<int> x, IEnumerable<int> y)
    {
        return x.OrderBy(i => i).SequenceEqual(y.OrderBy(i => i));
    }

    public int GetHashCode(IEnumerable<int> obj)
    {
        return obj.Sum(i => i * i);
    }
}

重要的是GetHashCode()应该是 O(N),排序会太慢。

于 2011-08-04T20:58:25.577 回答
1
void Main()
{
    var query =     from a in new int[] { 1 }
                    from b in new int[] { 2, 3 }
                    from c in new int[] { 2, 3 }
                    from d in new int[] { 4 }                   
                    from e in new int[] { 2, 3 }
                    select new int[] { a, b, c, d, e }; 
    query.Distinct(new ArrayComparer());
        //.Dump();
}
 public class ArrayComparer : IEqualityComparer<int[]>
    {
        public bool Equals(int[] x, int[] y)
        {            
            if (x == null || y == null)
                return false;

            return x.OrderBy(i => i).SequenceEqual<int>(y.OrderBy(i => i));

        }

        public int GetHashCode(int[] obj)
        {
            if ( obj == null || obj.Length == 0)
                return 0;
            var hashcode = obj[0];
            for (int i = 1; i < obj.Length; i++)
            {
                hashcode ^= obj[i];
            }
            return hashcode;
        }
    }
于 2011-08-04T21:15:17.433 回答
1

对整个多重集组合的最终解决方案,然后修剪结果集以删除重复问题,最终作为静态方法在帮助类中结束。它采用了 svick 非常受欢迎的答案,并将 IEqualityComparer 依赖项注入到我在 Eric Lipperts 的博客中找到的现有 CartesianProduct 答案中我建议阅读他的帖子,因为它解释了他的思想中的迭代以及为什么 linq 实现是最好的)。

static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences,
                                                       IEqualityComparer<IEnumerable<T>> sequenceComparer)
{
    IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
    var resultsSet = sequences.Aggregate(emptyProduct, (accumulator, sequence) => from accseq in accumulator
                                                                                  from item in sequence
                                                                                  select accseq.Concat(new[] { item }));

    if (sequenceComparer != null)
        return resultsSet.Distinct(sequenceComparer);
    else
        return resultsSet;
}
于 2013-09-07T07:45:44.067 回答