LINQ implementation of Cartesian Product with pruning

后端 未结 3 763
盖世英雄少女心
盖世英雄少女心 2021-01-22 03:23

I hope someone is able to help me with what is, at least to me, quite a tricky algorithm.

The Problem

I have a List (1 <= size <= 5, but siz

相关标签:
3条回答
  • 2021-01-22 03:52

    You should implement your own IEqualityComparer<IEnumerable<int>> and then use that in Distinct().

    The choice of hash code in the IEqualityComparer depends on your actual data, but I think something like this should be adequate if your actual data resemble those in your examples:

    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);
        }
    }
    

    The important part is that GetHashCode() should be O(N), sorting would be too slow.

    0 讨论(0)
  • 2021-01-22 03:52
    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;
            }
        }
    
    0 讨论(0)
  • 2021-01-22 04:02

    The finalised solution to the whole combining of multisets, then pruning the result-sets to remove duplicates problem ended up in a helper class as a static method. It takes svick's much appreciated answer and injects the IEqualityComparer dependency into the existing CartesianProduct answer I found at Eric Lipperts's blog here (I'd recommend reading his post as it explains the iterations in his thinking and why the linq implimentation is the best).

    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;
    }
    
    0 讨论(0)
提交回复
热议问题