Search in dictionary of dictionaries - c#

I have a dictionary defined as seen here:
Dictionary<int, Dictionary<string, object>> dict = new Dictionary<..>();
And a sample code for adding data:
dict.Add (X, new Dictionary<string, object> ());
dict [X].Add ("Car", CarObject);
dict [X].Add ("Seller", SellerObject);
dict [X].Add ("Key3", Z);
I want to search in the inner dictionary if it contains an object which then contains the following
CarObject.Name = (wildcard)X1(wildcard) of the key "Car" but I just can't seem to get a grasp of how to get into the inner dictionary and then into the object with LINQ in order to search for the value.

This will return all matching KeyValuePair<string, object>.
var query = dict.SelectMany(d => d.Value)
.Where(i => i.Key == "Key1"
&& (
i.Value is CarObject
? ((CarObject)i.Value).Name.Contains("X1")
: false
));

Try the following:
var results = dict[X].Where(x => (x.Value is CarObject) && ((CarObject)x.Value).Name.Contains("X1"));
If you want to get just the value and not the dictionary, and print the values, you can do this:
int X = 0, Z = 1;
dict[X].Add("Key1", CarObject);
dict[X].Add("Key2", SellerObject);
dict[X].Add("Key3", Z);
var results = dict[X].Where(x => (x.Value is CarObject) && ((CarObject)x.Value).Name.Contains("X1")).Select(x => x.Value);
foreach (var str in results)
Console.WriteLine(str);

You can try something like:
dict[X].Where(x => x.Value is CarObject && ((CarObject)x.Value).Name.Contains("X1"));
Or:
dict[X].Values.OfType<CarObject>().Any(x => x.Name.Contains("X1"))

Related

One line code of List<Dictionary<string, object>> to List<string>

Is there a shortest way to do this. Because I want to get only a certain key from dictionary
List<Dictionary<string, object> channel = DatabaseFunction.Select(some parameter);
List<string> result = new List<string>();
for (int i = 0; i < channel.Count; i++)
{
result.Add(channel[i]["key"].ToString());
}
Assuming that "key" always exists in all Dictionary<String,Object> objects in channel and always has a non-null object reference:
List<String> result = channel
.Select( dict => dict["key"].ToString() )
.ToList();
A safer version, which skips-over dictionary elements without "key" and/or when the inner Object is null would be:
List<String> result = channel
.Select( dict => ( ok: dict.TryGetValue( "key", out Object? obj ), obj ) )
.Where( t => t.ok && t.obj != null )
.Select( t => t.obj!.ToString() )
.ToList();
You can use Select instead of for loop
List<Dictionary<string, object> channel = DatabaseFunction.Select(some parameter);
List<string> result = channel.Select(item => item["key"].ToString()).ToList()
You can have the key check before adding it to the list with Where for safety
List<Dictionary<string, object> channel = DatabaseFunction.Select(some parameter);
List<string> result = channel
.Where(dict => dict.ContainsKey("key"))
.Select(item => item["key"].ToString()).ToList()

Remove same value in Lists within a Dictionary in C# - LINQ

I have the next Dictionary of List:
Dictionary<int, List<int>> links_dict = new Dictionary<int, List<int>>();
This object has these values:
1:{[7,8,3]},2:{[1,3]},3:{[4,8]},4:{[8]}
Is there a LINQ way for remove the same value of all lists within a Dictionary?
For example if I remove '8' from it, the new Dictionary will be:
1:{[7,3]},2:{[1,3]},3:{[4]}
You can just re-project
var results = links_dict.ToDictionary(x => x.Key, x => x.Value.Where(y => y != 8).ToList());
If you need to remove the empty keys, you could check after the fact. It might give you better performance
foreach (var item in results.Where(item => item.Value?.Any() != true))
results.Remove(item.Key);
Or
var results = links_dict.Select(x => (x.Key, x.Value.Where(y => y != 8).ToList()))
.Where(x => x.Item2?.Any() == true)
.ToDictionary(x => x.Item1, x => x.Item2);
Or keeping the original Dictionary
foreach (var key in links_dict.Keys.ToList())
links_dict[key] = links_dict[key].Where(x => x != 8).ToList();
foreach (var item in links_dict.Where(item => item.Value?.Any() != true).ToList())
links_dict.Remove(item.Key);

How to find duplicate values in List<Dictionary<string, object>>?

I have a List of Dictionary<string, object>.
How to find duplicate values in all dictionaries by value?
You can find duplicate values with their occurrences using LINQ.
It gives you duplicate values and its occurrences (index in list and key in dictionary).
var duplicates = dicList
.SelectMany((x, i) => x.Select(p => new { Index = i, Key = p.Key, Value = p.Value }))
.GroupBy(x => x.Value)
.Where(x => x.Count() > 1)
.Select(x => new
{
Value = x.First().Value,
Occurrences = x.Select(o => new { Index = o.Index, Key = o.Key })
});
If you just want duplicate values then use simplified version
var duplicates = listOfDic
.SelectMany(x => x.Values)
.GroupBy(x => x)
.Where(x => x.Count() > 1);
Old classic loop
var uniqueValues = new HashSet<object>();
var duplicateValues = new List<object>();
foreach (var value in yourDictionaries.SelectMany(dict => dict.Values))
{
if (uniqueValues.Add(value) == false)
{
duplicateValues.Add(value);
}
}
SelectMany is a key method for getting all values of all dictionaries.
If you are fan of LINQ you can convert it to the LINQ expression for example by using Aggregate or GroupBy
Use linq for compact code:
List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
list.SelectMany(dictionary => dictionary.Values).GroupBy(d => d).Where(x => x.Count() >1);

Checking a dictionary if there are same values for a key

I have a dictionary object like this:
CustomKeys<int, string>
eg;
1000, F1
1001, F2
1002, F1
1003, F4
1004, F2
I want to know if I have more than 1 of same values in this dictionary. I would also want to keep a note of which keys(unique id) has duplicates.
Is that possible?
It is possible using GroupBy and than Count() > 1 to keep track of which values that have duplicates.
var q = dic.GroupBy(x => x.Value)
.Select (x => new { Item = x, HasDuplicates = x.Count() > 1 });
You can find all key values they had the same values like this;
Dictionary<int, string> d = new Dictionary<int, string>();
d.Add(1000, "F1");
d.Add(1001, "F2");
d.Add(1002, "F1");
d.Add(1003, "F4");
d.Add(1004, "F2");
var dublicate = d.ToLookup(x => x.Value, x => x.Key).Where(x => x.Count() > 1);
foreach (var i in dublicate)
{
Console.WriteLine(i.Key);
}
Here is a DEMO.
But if you want to get a boolean value since your item's has a same value, look at Magnus's answer which is great.
I'm not sure by what you mean by "keeping note of which has duplicate values". If you mean keeping note of the keys, you could do this:
var keys = new Dictionary<int, string>();
keys.Add(1000, "F1");
keys.Add(1001, "F2");
keys.Add(1002, "F1");
keys.Add(1003, "F4");
keys.Add(1004, "F2");
var duplicates = keys.GroupBy(i => i.Value).Select(i => new
{
keys = i.Select(x => x.Key),
value = i.Key,
count = i.Count()
});
foreach (var duplicate in duplicates)
{
Console.WriteLine("Value: {0} Count: {1}", duplicate.value, duplicate.count);
foreach (var key in duplicate.keys)
{
Console.WriteLine(" - {0}", key);
}
}
If you mean keeping track of the duplicate values only, see Sonor's answer.
Another solution could be:
var duplicates = dictionary.GroupBy( g => g.Value )
.Where( x => x.Count( ) > 1 )
.Select( x => new { Item = x.First( ), Count = x.Count( ) } )
.ToList( );

parsing string and create Dictionary

I have the following string pattern: 1:2,2:3.
This is like array in one string:
The first element is: 1:2
The second element is: 2:3
I want to parse it and create a dictionary:
1,2 // 0 element in Dictionary
2,3 // 1 element in Dictionary
This is my code:
Dictionary<int,int> placesTypes = new Dictionary<int, int>();
foreach (var place in places.Split(','))
{
var keyValuePair = place.Split(':');
placesTypes.Add(int.Parse(keyValuePair[0]), int.Parse(keyValuePair[1]));
}
Is there the best way to do this?
Thanks.
You could change it to this:
var d = s.Split(',')
.Select(x => x.Split(':'))
.ToDictionary(x => int.Parse(x[0]), x => int.Parse(x[1]));
Dictionary<int, int> dict = "1:2,2:3".Split(',')
.Select(x => x.Split(':'))
.ToDictionary(x => int.Parse(x[0]),
x => int.Parse(x[1]));
var result = input.Split(new[]{','})
.Select(s => s.Split(new[]{':'}))
.ToDictionary(k => int.Parse(k[0]), v=> int.Parse(v[1]));
Live example: http://rextester.com/GTKO60478
If you're using C# >= 3.5 the ToDictionary LINQ method is the way to go:
var dictionary = places.Split(',')
.Select(place => place.Split(':'))
.ToDictionary(keyValue => int.Parse(keyValue[0]), keyValue => int.Parse(keyValue[1]));
Failing that, the following should suffice:
public static Dictionary<string, string> ToDictionary(string value, char pairSeperator, char valueSeperator)
{
Dictionary<int, int> dictionary = new Dictionary<int, int>();
foreach (string pair in value.Split(pairSeperator))
{
string[] keyValue = pair.Split(valueSeperator);
dictionary.Add(keyValue[0], keyValue[1]);
}
return dictionary;
}
Splitting only once, using MoreLinq.Batch
Dictionary<int, int> dict = places.Split(',', ':').Batch(2).Select(x=>x.ToArray()).ToDictionary(x=>int.Parse(x[0]),x=>int.Parse(x[1]));

Categories