0

I want to store the duplicated values of an Array, or what is the same I want to delete the Unique names.

For example if I have an Array with this content:

{a, b, c, c, c}

I want to store this in other array:

{c, c, c}

I know how to perform the operation using a For loop but I want to improve the code using LINQ extensions (if is possibly).

2
  • So, the original array just keeps {a, b}, not even a single c? Also, is the input sorted? What's the performance requirements? (Because if performance is any factor, I suggest a loop + Array.Resize) Commented Sep 7, 2013 at 21:53
  • @sehe, really no matter if the first array keeps the C or not while the new array contains the duplicated value 1 time, yes the array is sorted, like I've said I don't preffer to use For having he usefull LINQ extensions to improve it, thanks for comment. Commented Sep 7, 2013 at 22:33

2 Answers 2

2

This does what you want, but will reorder the elements in your original collection.

var query = yourArray.GroupBy(x=>x)
     .Where(x=>x.Count() > 1)
     .SelectMany(x=>x)
     .ToArray();

To get the difference between the two, you can then use Except, doing:

var exceptResult = yourArray.Except(query);
Sign up to request clarification or add additional context in comments.

3 Comments

Yes, this is what I had in mind for "non-performant". Yet, several helpless performance kittens are weeping silently in a corner. Really, with the input sorted, a simple one-pass algorithm would be so much more performant, and arguably more clear...
@sehe Well I agree that this problem doesn't really requires LINQ. But since he asked for a LINQ solution, I provided it :) It should be enough to have the performance remark in the comments, to remember everybody that's not the ideal way to do it
I've tried something like array1.except(array1.distinct) but does not worked, I comment that 'cause if you can have a better performance idea using linq, you guys consider that in an Array which can have around 100 entries (NO MORE) using @Save code can be a too much negative point of performance?
1

(In C#) this a much faster implementation then doing a GroupBy/Where/SelectMany (and a Count() that enumerates). But I must agree that it is more code ;-)

var array = new[] { 1, 2, 3, 3, 3 };
var valueCounter = new ValueCounter<int>(array);
var query = valueCounter.Where(p => p.Value > 1)
    .SelectMany(p => Enumerable.Repeat(p.Key, p.Value)).ToArray();

Using this ValueCounter class:

public class ValueCounter<T> : IEnumerable<KeyValuePair<T, int>>
{
    private readonly IEqualityComparer<T> _comparer;
    private readonly Dictionary<T, int> _valueCounter;
    private int _nullCount = 0;

    public ValueCounter(IEnumerable<T> values, IEqualityComparer<T> comparer)
    {
        _comparer = comparer ?? EqualityComparer<T>.Default;
        _valueCounter = new Dictionary<T, int>(_comparer);
        if (values != null)
        {
            foreach (var value in values)
            {
                Add(value);
            }
        }
    }

    public ValueCounter(IEqualityComparer<T> comparer)
        : this(null, comparer)
    {
    }

    public ValueCounter(IEnumerable<T> values)
        : this(values, null)
    {
    }

    public ValueCounter()
        : this(null, null)
    {
    }

    public void Add(T value)
    {
        if (value == null)
        {
            _nullCount++;
        }
        else
        {
            int count;
            if (_valueCounter.TryGetValue(value, out count))
            {
                _valueCounter[value] = count + 1;
            }
            else
            {
                _valueCounter.Add(value, 1);
            }
        }
    }

    /// <summary>
    /// Removes a value 
    /// </summary>
    /// <param name="value">The value that needs to be removed</param>
    /// <returns>True if a value was removed</returns>
    public bool Remove(T value)
    {
        if (value == null)
        {
            if (_nullCount > 0)
            {
                _nullCount--;
                return true;
            }
        }
        else
        {
            int count;
            if (_valueCounter.TryGetValue(value, out count))
            {
                if (count == 1)
                {
                    _valueCounter.Remove(value);
                }
                else
                {
                    _valueCounter[value] = count - 1;
                }
                return true;
            }
        }
        return false;
    }

    public int GetCount(T value)
    {
        int result;
        _valueCounter.TryGetValue(value, out result);
        return result;
    }

    public IEnumerator<KeyValuePair<T, int>> GetEnumerator()
    {
        return _valueCounter.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.