0

I've got List<double[]> and I want to create new list with arrays, witch are exactly the same. I try this way:

var query = li.GroupBy(x => x)
               .Where(g => g.Count() > 1)
               .Select(y => y.Key)
               .ToList();

But after all list query has 0 elements... What am I doing wrong?

Ok, so:

list[0] = double[4] {1.4,0.5,3.6,1.2},
list[1] = double[4] {0.3,0.4,3.1,1.2}
list[2] = double[4] {1.4,0.5,3.6,1.2}

And in my new list I want only:

new_list[0] = double[4] {1.4,0.5,3.6,1.2}
Grant Winney
  • 65,241
  • 13
  • 115
  • 165
Ann
  • 79
  • 10
  • 2
    What do you mean by *which are exactly the same*? Could you provide sample input and desired output? – MarcinJuraszek Jan 26 '14 at 18:23
  • Ok, so list[0] = double[4] {1.4,0.5,3.6,1.2}, list[1]= double[4] {0.3,0.4,3.1,1.2} list[2]=double[4] {1.4,0.5,3.6,1.2} And in my new list I want only: new_list[0]=double[4] {1.4,0.5,3.6,1.2} – Ann Jan 26 '14 at 18:25
  • Are you trying to get a single copy of any array from your set that has a duplicate elsewhere in the set, and not all distinct arrays?Restated, why is `list[1]` not part of your example output? Also, does the order of the elements in the array matter for your definition of equivalent? Your code as written currently doesn't do what you want because you're using default equality comparisons in your `GroupBy` clause, which for arrays is reference equality. – Preston Guillot Jan 26 '14 at 18:40
  • @Ann, could you please answer this question: do you want duplicate arrays or duplicate values ? what should be the final result, `List` or `List` ???? – Selman Genç Jan 26 '14 at 19:30

5 Answers5

1
List<double[]> lists = new List<double[]>{
    new[]{1.4,0.5,3.6,1.2},
    new[]{0.3,0.4,3.1,1.2},
    new[]{1.4,0.5,3.6,1.2}
};

var query = lists.SelectMany(x => x) // <-- You need this
                .GroupBy(x => x)
                .Where(g => g.Count() > 1)
                .Select(y => y.Key)
                .ToList();
L.B
  • 114,136
  • 19
  • 178
  • 224
  • It returns correct result for sample input, but I'm not 100% that's what OP needs. Consider following input: `var list = new List { new[] { 0.1, 0.2 }, new[] { 0.2, 0.3 } };`. You code would return `0.2`, but I think OP wants it to return empty list. – MarcinJuraszek Jan 26 '14 at 18:33
  • This is the correct answer; the "SelectMany" at the beginning is required, to merge all the items into a single collection before grouping and selecting them. OP's example at the bottom of the question confirms this is the output he is expecting. – BTownTKD Jan 26 '14 at 18:36
  • @MarcinJuraszek Of course we answer making some assumptions. Why don't you post an answer so that OP can choose whichever he/she likes. – L.B Jan 26 '14 at 18:36
  • 1
    @L.B I would post my answer if I knew how to solve the problem I think OP is facing. `GroupBy` by entire array content? That's not something that can be solved easily (at least I can't see an easy way). – MarcinJuraszek Jan 26 '14 at 18:37
  • This is not what the OP asks for, he is clearly wants to duplicate arrays not duplicate values.I tried your code with seven arrays (see my screenshot) and it return 8 value – Selman Genç Jan 26 '14 at 19:21
  • @Selman22 `This is not what the OP asks for` Maybe, but as mentioned already, the question is not clear. How can you be so sure? – L.B Jan 26 '14 at 19:23
  • @L.B `I've got List I want to create new list with arrays, witch are exactly the same.` my main language is not english but I can understand from this sentence he/she wants to list of arrays,not list of doubles – Selman Genç Jan 26 '14 at 19:25
  • @Selman22 OK, As I said already, this approach can be correct as MarcinJuraszek mentioned long ago before you. but I find downvoting for this reason not polite. So I did the same. – L.B Jan 26 '14 at 19:28
1

You should use a custom equality comparer to find duplicates when they are complex objects such as arrays.

    class DoubleArrayComparer : IEqualityComparer<double[]>
    {
        private DoubleArrayComparer() { }

        public static readonly DoubleArrayComparer Instance = new DoubleArrayComparer();

        public bool Equals(double[] x, double[] y)
        {
            return Enumerable.SequenceEqual(x, y);
        }

        public int GetHashCode(double[] obj)
        {
            //TODO: should implement better
            return 0;
        }
    }

    static void Main(string[] args)
    {
        List<double[]> li = new List<double[]>{
            new[]{1.4,0.5,3.6,1.2},
            new[]{0.3,0.4,3.1,1.2},
            new[]{1.4,0.5,3.6,1.2}
        };

        var query = li.GroupBy(x => x, DoubleArrayComparer.Instance)
            .Where(g => g.Count() == 1)
            .Select(y => y.Key)
            .ToList();
    }
fejesjoco
  • 11,763
  • 3
  • 35
  • 65
0

If I understand your question correctly you need only arrays that are duplicated in input query. Because there is no easy way to group by the entire array content, you can try transforming array to string and group by that string:

var results = list.GroupBy(a => String.Join(",", a.Select(d => d.ToString())))
                  .Where(g => g.Count() > 1)
                  .Select(g => g.First())
                  .ToList();
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
0

How about this solution ?

public class ArrayComparer : IEqualityComparer<double[]>
    {

        public bool Equals(double[] x, double[] y)
        {
            return x.SequenceEqual(y);
        }

        public int GetHashCode(double[] obj)
        {
            return base.GetHashCode();
        }
    }

var list = new double[] {1.4, 0.5, 3.6, 1.2};
var list2 = new double[] { 0.3, 0.4, 3.1, 1.2 };
var list3 = new double[] { 1.4, 0.5, 3.6, 1.2 };

var lst = new List<double[]> {list, list2, list3};

var newList = lst.Where(x => lst.Except(new List<double[]> {x}).Contains(x,new ArrayComparer()))
                         .Distinct(new ArrayComparer())
                         .ToList();

Another example in debug:

enter image description here enter image description here

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
-2

use Intersect

var query = lists.Select(x => x) 
            .Where(y => x.Intersect(y).Count == x.Count)
            .Select(y => y)
            .ToList();
  • this psaude code - when I will be near my Windows machine I can check this
Mzf
  • 5,210
  • 2
  • 24
  • 37
  • `.SelectMany(x => x)` returns `IEnumerable` so `double.Intersect(double)` is invalid. – L.B Jan 26 '14 at 18:51
  • No, Same problem. **Plus**, what is `x` in `Where` ? How about testing your code in VS or Linqpad? – L.B Jan 26 '14 at 18:54
  • @L.B, like I wrote , this is psaude code, the idea is simple - use build in Intersect. can test it since I'm on my Mac – Mzf Jan 26 '14 at 18:57
  • Mzf, We can see the idea but the question is how to do it. Implementing the idea may not be so simple. Either post a compilable code or not(since it is not a theoretical question). BTW: you can use mono on your mac. – L.B Jan 26 '14 at 19:06
  • L.B - since no one have mention this option I add the answer. I guess it would be easier to do it with Intersect rather than complicated linq. BTW - mono is not an option – Mzf Jan 26 '14 at 19:12