lighty
lighty

Reputation: 87

Occurance of Values in a Dictionary C#

Is there a way that I have a dictionary and I need to get only the pair that occurs more than once in Linq ? for example in

{1, "entries"},  
{2, "images"},
{3, "views"},
{4, "images"},
{5, "results"},
{6, "images"},
{7, "entries"}

I get

{1, "entries"}, 
{2, "images"},
{6, "images"},
{7, "entries"}

Upvotes: 3

Views: 1525

Answers (4)

Alex Siepman
Alex Siepman

Reputation: 2598

With these extension methods you have a (little bit) faster and general solution (works on all IEnumarable sources):

public static class Extensions
{
    public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
    {
        var grouped = source.GroupBy(selector);
        var moreThen1 = grouped.Where(i => i.IsMultiple());
        return moreThen1.SelectMany(i => i);
    }

    public static bool IsMultiple<T>(this IEnumerable<T> source)
    {
        var enumerator = source.GetEnumerator();
        return enumerator.MoveNext() && enumerator.MoveNext();
    }
}

Fill the source:

// Create the source
var dictionary = new Dictionary<int, string>
    {
        {1, "entries"},
        {2, "images"},
        {3, "views"},
        {4, "images"},
        {5, "results"},
        {6, "images"},
        {7, "entries"}
    };

Here are 3 options (each option is improved):

// More or less the same solution as other answers
var multiples1 = dictionary.GroupBy(p => p.Value)
                            .Where(g => g.Count() > 1)
                            .SelectMany(g => g);

// A little bit faster because IsMultiple does not enumerate all values 
// (Count() iterates to the end, which is not needed in this case).
var multiples2 = dictionary.GroupBy(p => p.Value)
                            .Where(g => g.IsMultiple())
                            .SelectMany(g => g);

// Easy to read
var multiples3 = dictionary.Duplicates(p => p.Value);

Upvotes: 0

Jon
Jon

Reputation: 437386

If you mean only the values that occur more than once, you can do group the key/value pairs by value, filter out the groups with only one item and select the common group key (original value that appears multiple times) from what remains:

var multiples = dictionary.GroupBy(p => p.Value)
                          .Where(g => g.Count() > 1)
                          .Select(g => g.Key);

If you want all pairs of keys/values where the values occur more than once, this variation will do it:

var multiples = dictionary.GroupBy(p => p.Value)
                          .Where(g => g.Count() > 1)
                          .SelectMany(g => g);

The only difference is in the last step, where after casting out groups with just one value the contents of all remaining groups are "unwrapped" into a single sequence of key/value pairs.

In the latter case, you can turn the results back into a dictionary (essentially filtering out values that appear only once) by following up with

.ToDictionary(p => p.Key, p => p.Value)

The last example, in query form:

var multiples = from pair in dictionary
                group pair by pair.Value into grp
                where grp.Count() > 1
                from pair in grp select pair;

Upvotes: 13

Giannis Paraskevopoulos
Giannis Paraskevopoulos

Reputation: 18411

Dictionary<int,string> d = new Dictionary<int,string>();
d.Add(1, "entries");
d.Add(2, "images");
d.Add(3, "views");
d.Add(4, "images");
d.Add(5, "results");
d.Add(6, "images");
d.Add(7, "entries");

d.GroupBy(x => x.Value)
 .Where(x=>x.Count()>1)
 .SelectMany(x => x)
 .ToDictionary
 (
     x => x.Key,
     x=>x.Value
 );

Upvotes: 0

roman
roman

Reputation: 117380

var res = dict.GroupBy(x => x.Value).Where(y => y.Count() > 1);

if you want to get a Dictionary:

var res = dict.GroupBy(x => x.Value)
              .Where(y => y.Count() > 1)
              .SelectMany(z => z)
              .ToDictionary(k => k.Key, k => k.Value);

Upvotes: 2

Related Questions