How to find out Union of Dictionary Values in C#? - c#

I need to find out Union of dictionary Values. I have created the dictionary below.
Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>();
List<string> ls1 = new List<string>();
ls1.Add("1");
ls1.Add("2");
ls1.Add("3");
ls1.Add("4");
List<string> ls2 = new List<string>();
ls2.Add("1");
ls2.Add("5");
dict.Add(1, ls1);
dict.Add(2, ls2);
So in this case Output would be {"1","2","3","4","5"}

As a Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>> you may use Linq.
The following Linq will get what you are after:
dict.SelectMany(kvp => kvp.Value).Distinct()
The SelectMany will select all of the elements of the lists, the Distinct() ensures duplicate elements are only returned once.
As stated in the comment, you require a List<string> of the result, so the code may be extended to:
var result = dict.SelectMany(kvp => kvp.Value).Distinct().ToList();

You just need to flatten the values and eliminate the duplicates using Distinct:
dict.SelectMany(x => x.Value).Distinct();

To get union of your values, you could use LINQ Union:
dict.Values.Union(dict.Values);

Related

Order a dictionary without using Linq OrderBy

I'm trying to order a C# Dictionary<int, int> by its value without using LINQ's OrderBy as it's not supported on iPhones.
I can't seem to figure it out, so your help would be much appreciated!
There are many possible ways of doing this. All of the following assume myDictionary is the original dictionary to be sorted.
① Create a list and then sort the list
var myList = myDictionary.ToList();
myList.Sort((a, b) => a.Value.CompareTo(b.Value));
② Create an array and then sort the array
var myArray = myDictionary.ToArray();
Array.Sort(myArray, (a, b) => a.Value.CompareTo(b.Value));
③ Create a new SortedDictionary that has keys and values swapped
This solution is appropriate only if you know that every value occurs only once.
var mySortedDict = new SortedDictionary<int, int>();
foreach (var kvp in myDictionary)
mySortedDict[kvp.Value] = kvp.Key;
④ Create a new SortedDictionary and use lists for values
This solution is appropriate only if values can occur more than once.
var mySortedDict = new SortedDictionary<int, List<int>>();
foreach (var kvp in myDictionary)
{
if (!mySortedDict.ContainsKey(kvp.Value))
mySortedDict[kvp.Value] = new List<int>();
mySortedDict[kvp.Value].Add(kvp.Key);
}
We can generate a List of KeyValuePair and then sort it using Sort,
Dictionary<int, int> myList = new Dictionary<int, int>();
List<KeyValuePair<int, int>> mySortedList = myList.ToList();
mySortedList.Sort(( firstValue, nextValue) =>
{
return firstValue.Value.CompareTo(nextValue.Value);
}
);
Dictionary<int, int> mySortedDict = mySortedList.ToDictionary(keyItem => keyItem.Key, keyItem => keyItem.Value);
I think Sort will be supported on iPhones

How keys are reorganized after C# LINQ convert a dictionary to a query?

I am working on C# converting a dictionary to query :
public class myClass
{
public int my_id;
public Dictionary<string, Dictionary<string, string[]>> myDict;
}
Dictionary<string, myClass> dataDict;
var queryDict = (from happen in dataDict
group happen by happen.Value.my_id into g select g)
.ToDictionary(g => g.Key, g => g.ToDictionary(x => x.Key, x => x.Value));
I need to iterate every element of queryDict.
Before doing the query, for the same dataDict's key, there may be multiple myClass that have the same event_id.
After query, for the same happen.Value.my_id, how the dataDict' s original keys are organized ? They are a list pointed by the one event_id ?
Any help would be appreciated !
Effectively, your dataDict is an array of KeyValuePair (1-dimensonal array). And your query adds another dimension, so it becomes a Dictionary of Dictionaries. But adding another dimension is just a grouping of older elements by a new key.
It's better to illustrate it like this:
Basically group by gives you an IGrouping<TKey, TElement> which is an IEnumerable<TElement> (IGrouping Interface), so having this query:
from happen in dataDict group happen by happen.Value.my_id into g select g
means, you group by happen.Value.my_id, so the TKey will be my_id and the TElement would be a KeyValuePair<string, MyClass>> which is the items of your dictionary. Since the IGrouping<int, KeyValuePait<stirng, MyClass>> which is the result of above query is actually an IEnumerable<keyValuePair<string, MyClass>>, so for every key you actually have an IEnumerable<KeyValuePair<string, MyClass>>. As you can see here, you have the elements of you dictionary as they were.
Second part of the query is just converting the IEnumerable<IGrouping<int, Dictionary<string, MyClass>>> to a Dictionary<int, Dictionary<string, MyClass>>> so it's not big deal.

Casting a Dictionary<int, List<User>>

What is the most efficient way to cast a Dictionary<int, List<User>> to a Dictionary<int, IEnumerable<User>>?
The reason for this is that I have a method which builds a Dictionary<int, List<User>> but I would prefer not to return a mutable List to the calling code.
Would I have to project this dictionary into the new type?
You can do just like this:
var userDictionary = new Dictionary<int, List<User>>();
IDictionary<int, IEnumerable<User>> newDictionary = userDictionary.ToDictionary(p => p.Key, p => p.Value.AsEnumerable());
You can return an IEnumerable but under the hood it'll be a List. A developer may well cast it to a List and add or remove items
I think you're looking for Immutable Collections
Briefly, it's a nuget package that enable us to use/create truly immutable collections; meaning that any collections changes are not reflected back to what exposed them.
EDIT: Cast to IEnumerable does not grant immutability
Given Guilherme Oliveira answer one can do the following and add a new user to the users
var userDictionary = new Dictionary<int, List<User>>();
userDictionary.Add(1, new List<User>
{
new User{ Name= "Joseph"},
});
IDictionary<int, IEnumerable<User>> newDictionary = userDictionary.ToDictionary(p => p.Key, p => p.Value.AsEnumerable());
((List<User>) newDictionary.Values.First()).Add(new User {Name = "Maria"});
Console.WriteLine(newDictionary.Values.First().Count()); //now we have two users
You would need to project this to a new dictionary, e.g.
Dictionary<int, List<User>> myDictionary = ...;
Dictionary<int, IEnumerable<User>> resultingDictionary = myDictionary.ToDictionary(kvp => kvp.Key, kvp => (IEnumerable<User>)kvp.Value)
You are unable to perform a cast from Dictionary<int, List<User>> to Dictionary<int, IEnumerable<User>> because if you could, the following would be possible:
Dictionary<int, List<User>> myDictionary = ...;
// Still a reference to the original dictionary
Dictionary<int, IEnumerable<User>> castDictionary = myDictionary;
// If the line above was possible, what would this do? (A HashSet<T> is not a List<T>)
castDictionary.Add(5, new HashSet<User>());
You may also want to take a look at covariance and contravariance on interfaces to see where the limitations lie.

Making a list distinct in C#

In C#, I have an object type 'A' that contains a list of key value pairs.
The key value pairs is a category string and a value string.
To instantiate object type A, I would have to do the following:
List<KeyValuePair> keyValuePairs = new List<KeyValuePair>();
keyValuePairs.Add(new KeyValuePair<"Country", "U.S.A">());
keyValuePairs.Add(new KeyValuePair<"Name", "Mo">());
keyValuePairs.Add(new KeyValuePair<"Age", "33">());
A a = new A(keyValuePairs);
Eventually, I will have a List of A object types and I want to manipulate the list so that i only get unique values and I base it only on the country name. Therefore, I want the list to be reduced to only have ONE "Country", "U.S.A", even if it appears more than once.
I was looking into the linq Distinct, but it does not do what I want because it I can't define any parameters and because it doesn't seem to be able to catch two equivalent objects of type A. I know that I can override the "Equals" method, but it still doesn't solve the my problem, which is to render the list distinct based on ONE of the key value pairs.
To expand upon Karl Anderson's suggestion of using morelinq, if you're unable to (or don't want to) link to another dll for your project, I implemented this myself awhile ago:
public static IEnumerable<T> DistinctBy<T, U>(this IEnumerable<T> source, Func<T, U>selector)
{
var contained = new Dictionary<U, bool>();
foreach (var elem in source)
{
U selected = selector(elem);
bool has;
if (!contained.TryGetValue(selected, out has))
{
contained[selected] = true;
yield return elem;
}
}
}
Used as follows:
collection.DistinctBy(elem => elem.Property);
In versions of .NET that support it, you can use a HashSet<T> instead of a Dictionary<T, Bool>, since we don't really care what the value is so much as that it has already been hashed.
Check out the DistinctBy syntax in the morelinq project.
A a = new A(keyValuePairs);
a = a.DistinctBy(k => new { k.Key, k.Value }).ToList();
You need to select the distinct property first:
Because it's a list inside a list, you can use the SelectMany. The SelectMany will concat the results of subselections.
List<A> listOfA = new List<A>();
listOfA.SelectMany(a => a.KeyValuePairs
.Where(keyValue => keyValue.Key == "Country")
.Select(keyValue => keyValue.Value))
.Distinct();
This should be it. It will select all values where the key is "Country" and concat the lists. Final it will distinct the country's. Given that the property KeyValuePairs of the class A is at least a IEnumerable< KeyValuePair< string, string>>
var result = keyValuePairs.GroupBy(x => x.Key)
.SelectMany(g => g.Key == "Country" ? g.Distinct() : g);
You can use the groupby statement. From here you can do all kind off cool stuf
listOfA.GroupBy(i=>i.Value)
You can groupby the value and then sum all the keys or something other usefull

Dictionary Manipulation Using LINQ in C#

I'm having a Dictionary like
Dictionary<String, List<String>> MyDict = new Dictionary<string, List<string>>
{
{"One",new List<String>{"A","B","C"}},
{"Two",new List<String>{"A","C","D"}}
};
I need to get a List<String> from this dictionary, The List should contain Distinct items from the values of the above dictionary.
So the resulting List will contain {"A","B","C","D"}.
Now I'm using for loop and Union operation. Like
List<String> MyList = new List<string>();
for (int i = 0; i < MyDict.Count; i++)
{
MyList = MyList.Union(MyDict[MyDict.Keys.ToList()[i]]).Distinct().ToList();
}
Can any one suggest me a way to do this in LINQ or LAMBDA Expression.
var items=MyDict.Values.SelectMany(x=>x).Distinct().ToList();
Or an alternative:
var items = (from pair in MyDict
from s in pair.Value
select s).Distinct().ToList();

Categories

Resources