How to Compare Key/Value Dictionary With == Operator on a Ireadonlycollection<String>

Get Dictionary key by using the dictionary value

A dictionary is really intended for one way lookup from Key->Value.

You can do the opposite use LINQ:

var keysWithMatchingValues = dic.Where(p => p.Value == "a").Select(p => p.Key);

foreach(var key in keysWithMatchingValues)
Console.WriteLine(key);

Realize that there may be multiple keys with the same value, so any proper search will return a collection of keys (which is why the foreach exists above).

Better datatype than a dictionary with string as key, and a list as value

If your list represents related values that share some common behavior, you may benefit from encapsulating this list in a class:

class SensorData {
public IList<float> Values {get;}
public SensorData(IEnumerable<float> values) {
Values = values.ToList();
}
// Add some useful methods that operate on Values here
...
}

Now instead of making

IDictionary<string,List<float>>

you would make

IDictionary<string,SensorData>

which could potentially provide for better readability of your code.

compare dictionary objects and get the one with lowest value

Using LINQ should be quite easy. I'm assuming you need to parse unit_prices to int, be careful: This will throw an exception if the data cannot be converted to an int.

int result =  productsInCart.Select(x => int.Parse(x["unit_price"])).Min();

Finding 'Next Available' Key in a dictionary or related collection

You can use SortedList with Extension method for Adding to next automatically retrieved key.

Assuming Data structure be any object, with numeric key,

Following is ExtensionMethod for SortedList

public static class SortedListExtensions
{
///Add item to sortedList (numeric key) to next available key item, and return key
public static int AddNext<T>(this SortedList<int, T> sortedList, T item)
{
int key = 1; // Make it 0 to start from Zero based index
int count = sortedList.Count;

int counter=0;
do
{
if (count == 0) break;
int nextKeyInList = sortedList.Keys[counter++];

if (key != nextKeyInList) break;

key = nextKeyInList +1;

if (count == 1 || counter == count ) break;


if (key != sortedList.Keys[counter])
break;

} while (true);

sortedList.Add(key, item);
return key;
}

}

It can be used like following

  SortedList<int, string> x = new SortedList<int, string>();

x.Add(4, "BCD");
x.Add(6, "BCD");

x.AddNext("a");
x.AddNext("b");
x.AddNext("c");
x.AddNext("d");
x.AddNext("e");

foreach (var item in x)
Console.WriteLine(item.Key + " " + item.Value);

The output is

        1 a
2 b
3 c
4 BCD
5 d
6 BCD
7 e

You can use Dictionary, or any other data structure. In that case Double loop will be required. In case of SortedList, one loop is saved while searching key. This loop is internally used by SortedList.Add function using BinarySearch Algorithm.

Binary search is faster than looping all elements (for larger size data).

Get Dictionary key by using the dictionary value

A dictionary is really intended for one way lookup from Key->Value.

You can do the opposite use LINQ:

var keysWithMatchingValues = dic.Where(p => p.Value == "a").Select(p => p.Key);

foreach(var key in keysWithMatchingValues)
Console.WriteLine(key);

Realize that there may be multiple keys with the same value, so any proper search will return a collection of keys (which is why the foreach exists above).

C# Linq revers outer-key with inner-key for a dictionary with dictionary as value

Interesting one, I thought.. I'd use SelectMany to expand the nest to a { key1, key2, value } and then Aggregate to put it back together rather than GroupBy/ToDictionary

var r = nodeTypedContainer
.SelectMany(
kvpO => kvpO.Value,
(kvpO, kvpI) => new { KeyO = kvpO.Key, KeyI = kvpI.Key, kvpI.Value }
)
.Aggregate(
new Dictionary<string, Dictionary<string, List<int>>>(),
(seed, val) => {
if (seed.TryGetValue(val.KeyI, out var dictI))
dictI.Add(val.KeyO, val.Value);
else
seed[val.KeyI] = new() { { val.KeyO, val.Value } };
return seed;
}
);

Aggregate and to a lesser degree SelectMany, aren't often used I think, so it might warrant a bt of explanation.

SelectMany with one argument is quite simple: it converts a T[][] into a T[] so some nested list of lists (think like a list of people and each person has a list of pets) becomes a straight list of the nested items (10 people each with 20 pets in a list, becomes 1 list of 200 pets).

SelectMany with two arguments allows us access to the original person as well as the list of pets, which means we can access the higher level of nest as well as the lower. This means we can turn out a list of 200 pets, with each person repeated 20 times too

In this case it converts the data:

[
{
key: node1,
value: [{
key: k1
value: [1, 2, 3]
},{
key: k2
value: [2]
]
},
{
key: node2,
value: [{
key: k1
value: [3]
}]
}
]

Into something like:

{ node1, k1, [1, 2, 3] }
{ node1, k2, [2] }
{ node2, k1, [3] }

No hierarchy now; repeating node1 instead.

Then we put it back together using Aggregate

  • The first argument to Aggregate is the new Dictionary<string, Dictionary<string, List<int>>> that we will output. It starts out as an empty dictionary, and we'll build it as we loop over every unnested item.
  • The second argument to Aggregate should be some code that modifies the current accumulating value, and returns it. We don't actually need a version that returns it because we always modify the contents of the seed we created rather than having an immutable style "take in the current iteration, prepare a new version based on it and return it for next time". To some extent it goes against "LINQ should not have side effects" but it's generally accepted at Aggregate can have this side effect and it's safe in the sense that we're modifying the instance we created in the seed. Be wary of using Aggregate on something mutable that was created elsewhere other than in the first argument

So the lambda for the second arg receives the new Dict<Dict>; it has to look up whether that outer dictionary contains the inner key (like k1, k2).. If it does then it should add the outer key and inner list as a new entry. If it doesn't then it should create a new inner Dictionary<string, List> initialized with the outer key and the inner List

Get key from value - Dictionary<string, List<string>>

The return value from FirstOrDefault will be a KeyValuePair<string, List<string>>, so to get the key, simply use the Key property. Like this:

var emailAdd = statesToEmailDictionary
.FirstOrDefault(x => x.Value.Contains(state))
.Key;

Alternatively, here's the equivalent in query syntax:

var emailAdd = 
(from p in statesToEmailDictionary
where p.Value.Contains(state)
select p.Key)
.FirstOrDefault();

LINQ: Getting Keys for a given list of Values from Dictionary and vice versa

 var values = dictionary.Where(x => someKeys.Contains(x.Key)).Select(x => x.Value);
var keys = dictionary.Where(x => someValues.Contains(x.Value)).Select(x => x.Key);


Related Topics



Leave a reply



Submit