This question already has answers here:
Get dictionary key by value
(11 answers)
Closed 4 years ago.
I have defined Enumand Dictionary as below.
Now in Dictionary, I want to get Key from Value using Linq
enum Devices
{
Fan,
Bulb,
Mobile,
Television
};
Dictionary<int, Devices> dctDevices = new Dictionary<int, Devices>()
{
{1, Devices.Fan},
{2, Devices.Bulb},
{3, Devices.Mobile},
{4, Devices.Television}
};
I want result like below. I need concrete method named below.
int key = GetKeyFromValue(Devices.Bulb);
Please suggest me the best way to perform this. Thanks in advance
The method could look like:
int GetKeyFromValue(Devices device)
{
return dctDevices.Keys
.Where(k => dctDevices[k] == device)
.DefaultIfEmpty( -1 ) // or whatever "not found"-value
.First();
}
or a generic extension method for any type:
public static TKey GetKeyByBalue<TKey, TValue>(this IDictionary<TKey, TValue> dict, TValue value, TKey notFoundKey, IEqualityComparer<TValue> comparer = null)
{
if (comparer == null)
comparer = EqualityComparer<TValue>.Default;
return dict.Keys.Where(k => comparer.Equals(dict[k], value)).DefaultIfEmpty(notFoundKey).First();
}
Note that you should use another dictionary if you want to lookup that value often:
Dictionary<Devices, int> DeviceKeys = new Dictionary<Devices, int>()
{
{Devices.Fan, 1}, // ...
};
Then the code becomes more efficient:
int key = DeviceKeys[Devices.Bulb];
Or create a custom class Device which encapsulates the ID and the Devices (and other things):
You can do it like below:
dctDevices.AsEnumerable().Where(p => p.Value == Devices.Bulb).FirstOrDefault().Key;
Related
This question already has answers here:
How to modify key in a dictionary in C#
(4 answers)
Closed 4 years ago.
I have a:
Dictionary<string, Dictionary<int, List<string>>> res = new Dictionary<string,
Dictionary<int, List<string>>>();
and I need to modify/change the int value of the nested Dictionary Key and keep all Dictionary values( List ) for the int Key.
If I understood everything correctly:
res[stringKey].Add(newKey, res[oldKey]);
res[stringKey].Remove(oldKey);
There is no native way to achieve this that I know of but you can try the following:
private void ModifyKey(int oldKey, int newKey, Dictionay<int, List<string>> dict)
{
var data = dict[oldKey];
// Now remove the previous data
dict.Remove(key);
try
{
dict.Add(newKey, data);
}
catch
{
// one already exists..., perhaps roll back or throw
}
}
You would then call the method as follows when you want to change the key:
// Assuming the dictionary is called myData
ModifyKey(5, 7, myData);
Suppose I have a class Building with properties int Id, int Height, int NumberOfFloors.
If I have a Dictionary, where each key is the building id. Is there a way to convert this into a Dictionary where each key is the building Id, and each value is the number of floors. Obviously this is feasible with a loop. Just wondering if there is a simple way to do this using lambdas?
Thanks!
var intToBuilding = new Dictionary<int, Building>(); //pretend populated
var intToInt = new Dictionary<int, int>();
foreach(var intBuilding in intToBuilding)
{
var building = userPreference.Value;
intToInt.Add(intBuilding.Key, building.Height);
}
It should go something like:
var floorDictionary = buildingDictionary
.ToDictionary(kv => kv.Key, kv => kv.Value.NumberofFloors);
The source dictionary implements IEnumerable< KeyValuePair<TKey, TValue> > and for that there is an extension method ToDictionary(keySelector, valueSelector).
I'm looking for a sorted list in C#, but when I inserting a item not sorting after insert all.
Neither SortedList nor Dictionary are suitable because I may have duplicate keys.
For example:
list.Insert(1001, v1);
list.Insert(1002, v2);
list.Insert(1002, v3);
list.Insert(1003, v4);
One possibility is to write a custom comparer which would allow duplicate keys in your collection:
public class DuplicateKeyComparer<TKey> : IComparer<TKey> where TKey : IComparable
{
public int Compare(TKey x, TKey y)
{
var res = x.CompareTo(y);
return res == 0 ? 1 : res;
}
}
and then use a SortedList<TKey, TValue>:
var comparer = new DuplicateKeyComparer<int>();
var list = new SortedList<int, string>(comparer);
list.Add(1001, "v1");
list.Add(1002, "v2");
list.Add(1002, "v3");
list.Add(1003, "v4");
Obviously there are culprits with this approach that you should be aware of - you will never be able to remove any key from this collection. So if you intend to use list.Remove(1002) as an example, then you will need an alternative approach.
Using the Values property of C# Dictionary,
var myDict = Dictionary < string, object> ;
How would I get the values in
myDict.Values
I tried
var theVales = myDict.Values ;
object obj = theValues[0] ;
But that is a syntax error.
Added:
I am trying to compare the values in two dictionaries that have
the same keys
You can't. The values do not have a fixed order. You could write the values into a new List<object> and index them there, but obviously that's not terribly helpful if the dictionary's contents change frequently.
You can also use linq: myDict.Values.ElementAt(0) but:
The elements will change position as the dictionary grows
It's really inefficient, since it's just calling foreach on the Values collection for the given number of iterations.
You could also use SortedList<TKey, TValue>. That maintains the values in order according to the key, which may or may not be what you want, and it allows you to access the values by key or by index. It has very unfortunate performance characteristics in certain scenarios, however, so be careful about that!
Here's a linq solution to determine if the values for matching keys also match. This only works if you're using the default equality comparer for the key type. If you're using a custom equality comparer, you can do this with method call syntax.
IEnumerable<bool> matches =
from pair1 in dict1
join pair2 in dict2
on pair1.Key equals pair2.Key
select pair1.Value.Equals(pair2.Value)
bool allValuesMatch = matches.All();
If you require that all items in one dictionary have a matching item in the other, you could do this:
bool allKeysMatch = new HashSet(dict1.Values).SetEquals(dict2.ValueS);
bool dictionariesMatch = allKeysMatch && allValuesMatch;
Well, you could use Enumerable.ElementAt if you really had to, but you shouldn't expect the order to be stable or meaningful. Alternatively, call ToArray or ToList to take a copy.
Usually you only use Values if you're going to iterate over them. What exactly are you trying to do here? Do you understand that the order of entries in a Dictionary<,> is undefined?
EDIT: It sounds like you want something like:
var equal = dict1.Count == dict2.Count &&
dict1.Keys.All(key => ValuesEqual(key, dict1, dict2));
...
private static bool ValuesEqual<TKey, TValue>(TKey key,
IDictionary<TKey, TValue> dict1,
IDictionary<TKey, TValue> dict2)
{
TValue value1, value2;
return dict1.TryGetValue(out value1) && dict2.TryGetValue(out value2) &&
EqualityComparer<TValue>.Default.Equals(value1, value2);
}
EDIT: Note that this isn't as fast as it could be, because it performs lookups on both dictionaries. This would be more efficient, but less elegant IMO:
var equal = dict1.Count == dict2.Count &&
dict1.All(pair => ValuesEqual(pair.Key, pair.Value, dict2));
...
private static bool ValuesEqual<TKey, TValue>(TKey key, TValue value1,
IDictionary<TKey, TValue> dict2)
{
TValue value2;
return dict2.TryGetValue(out value2) &&
EqualityComparer<TValue>.Default.Equals(value1, value2);
}
To add to #JonSkeet's answer, Dictionary<TKey, TValue> is backed by a HashTable, which is an un-ordered data structure. The index of the values is therefore meaningless- it is perfectly valid to get, say, A,B,C with one call and C,B,A with the next.
EDIT:
Based on the comment you made on JS's answer ("I am trying to compare the values in two dictionaries with the same keys"), you want something like this:
public boolean DictionariesContainSameKeysAndValues<TKey, TValue>(Dictionary<TKey, TValue> dict1, Dictionary<TKey, TValue> dict2) {
if (dict1.Count != dict2.Count) return false;
for (var key1 in dict1.Keys)
if (!dict2.ContainsKey(key1) || !dict2[key1].Equals(dict1[key1]))
return false;
return true;
}
You could use an Indexer propertie to lookup the string Key.
It is still not an Index but one more way:
using System.Collections.Generic;
...
class Client
{
private Dictionary<string, yourObject> yourDict
= new Dictionary<string, yourObject>();
public void Add (string id, yourObject value)
{ yourDict.Add (id, value); }
public string this [string id] // indexer
{
get { return yourDict[id]; }
set { yourDict[id] = value; }
}
}
public class Test
{
public static void Main( )
{
Client client = new Client();
client.Add("A1",new yourObject() { Name = "Bla",...);
Console.WriteLine ("Your result: " + client["A1"]); // indexer access
}
}
There doesn't seem to be a dictionary.AddRange() method. Does anyone know a better way to copy the items to another dictionary without using a foreach loop.
I'm using the System.Collections.Generic.Dictionary. This is for .NET 2.0.
There's the Dictionary constructor that takes another Dictionary.
You'll have to cast it IDictionary, but there is an Add() overload that takes KeyValuePair<TKey, TValue>. You're still using foreach, though.
There's nothing wrong with a for/foreach loop. That's all a hypothetical AddRange method would do anyway.
The only extra concern I'd have is with memory allocation behaviour, because adding a large number of entries could cause multiple reallocations and re-hashes. There's no way to increase the capacity of an existing Dictionary by a given amount. You might be better off allocating a new Dictionary with sufficient capacity for both current ones, but you'd still need a loop to load at least one of them.
var Animal = new Dictionary<string, string>();
one can pass existing animal Dictionary to the constructor.
Dictionary<string, string> NewAnimals = new Dictionary<string, string>(Animal);
For fun, I created this extension method to dictionary. This should do a deep copy wherever possible.
public static Dictionary<TKey, TValue> DeepCopy<TKey,TValue>(this Dictionary<TKey, TValue> dictionary)
{
Dictionary<TKey, TValue> d2 = new Dictionary<TKey, TValue>();
bool keyIsCloneable = default(TKey) is ICloneable;
bool valueIsCloneable = default(TValue) is ICloneable;
foreach (KeyValuePair<TKey, TValue> kvp in dictionary)
{
TKey key = default(TKey);
TValue value = default(TValue);
if (keyIsCloneable)
{
key = (TKey)((ICloneable)(kvp.Key)).Clone();
}
else
{
key = kvp.Key;
}
if (valueIsCloneable)
{
value = (TValue)((ICloneable)(kvp.Value)).Clone();
}
else
{
value = kvp.Value;
}
d2.Add(key, value);
}
return d2;
}
If you're dealing with two existing objects, you might get some mileage with the CopyTo method: http://msdn.microsoft.com/en-us/library/cc645053.aspx
Use the Add method of the other collection (receiver) to absorb them.
I don't understand, why not using the Dictionary( Dictionary ) (as suggested by ageektrapped ).
Do you want to perform a Shallow Copy or a Deep Copy? (that is, both Dictionaries pointing to the same references or new copies of every object inside the new dictionary?)
If you want to create a new Dictionary pointing to new objects, I think that the only way is through a foreach.
For a primitive type dictionary:
public void runIntDictionary()
{
Dictionary<int, int> myIntegerDict = new Dictionary<int, int>() { { 0, 0 }, { 1, 1 }, { 2, 2 } };
Dictionary<int, int> cloneIntegerDict = new Dictionary<int, int>();
cloneIntegerDict = myIntegerDict.Select(x => x.Key).ToList().ToDictionary<int, int>(x => x, y => myIntegerDict[y]);
}
or with an Object that implement ICloneable:
public void runObjectDictionary()
{
Dictionary<int, number> myDict = new Dictionary<int, number>() { { 3, new number(3) }, { 4, new number(4) }, { 5, new number(5) } };
Dictionary<int, number> cloneDict = new Dictionary<int, number>();
cloneDict = myDict.Select(x => x.Key).ToList().ToDictionary<int, number>(x => x, y => myDict[y].Clone());
}
public class number : ICloneable
{
public number()
{
}
public number(int newNumber)
{
nr = newnumber;
}
public int nr;
public object Clone()
{
return new number() { nr = nr };
}
public override string ToString()
{
return nr.ToString();
}
}
The reason AddRange is not implemented on Dictionary is due to the way in which a hashtable (i.e. Dictionary) stores its entries: They're not contiguous in memory as we see in an array or a List, instead they're fragmented across multiple hash buckets, so you cannot block-copy the whole range into a List or you'll get a bunch of empty entries which the Dictionary usually hides from you, the user, through its interface. AddRange assumes a single contiguous range of valid data and can therefore use a fast copy implementation e.g.Array.Copy (like C's memcpy).
Due to this fragmentation, we are left no choice but to iterate through the Dictionary's entries manually in order to extract valid keys and values into a single contiguous List or array. This can be confirmed in Microsoft's reference implementation, where CopyTo is implemented using for.