How to insert an item into a key/value pair object? - c#

I just need to be able to insert a key/value pair into an object at a specific position. I'm currently working with a Hashtable which, of course, doesn't allow for this functionality. What would be the best approach?
UPDATE: Also, I do need the ability to lookup by the key.
For example (oversimplified and pseudocoded but should convey the point):
// existing Hashtable
myHashtable.Add("somekey1", "somevalue1");
myHashtable.Add("somekey2", "somevalue2");
myHashtable.Add("somekey3", "somevalue3");
// Some other object that will allow me to insert a new key/value pair.
// Assume that this object has been populated with the above key/value pairs.
oSomeObject.Insert("newfirstkey","newfirstvalue");

List<KeyValuePair<string, string>> kvpList = new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("Key1", "Value1"),
new KeyValuePair<string, string>("Key2", "Value2"),
new KeyValuePair<string, string>("Key3", "Value3"),
};
kvpList.Insert(0, new KeyValuePair<string, string>("New Key 1", "New Value 1"));
Using this code:
foreach (KeyValuePair<string, string> kvp in kvpList)
{
Console.WriteLine(string.Format("Key: {0} Value: {1}", kvp.Key, kvp.Value);
}
the expected output should be:
Key: New Key 1 Value: New Value 1
Key: Key 1 Value: Value 1
Key: Key 2 Value: Value 2
Key: Key 3 Value: Value 3
The same will work with a KeyValuePair or whatever other type you want to use..
Edit -
To lookup by the key, you can do the following:
var result = stringList.Where(s => s == "Lookup");
You could do this with a KeyValuePair by doing the following:
var result = kvpList.Where (kvp => kvp.Value == "Lookup");

Maybe the OrderedDictonary will help you out.

Do you need to look up objects by the key? If not, consider using List<Tuple<string, string>> or List<KeyValuePair<string, string>> if you're not using .NET 4.

I would use the Dictionary<TKey, TValue> (so long as each key is unique).
EDIT: Sorry, realised you wanted to add it to a specific position. My bad. You could use a SortedDictionary but this still won't let you insert.

You could use an OrderedDictionary, but I would question why you would want to do that.

Use a linked list. It was designed for this exact situation.
If you still need the dictionary O(1) lookups, use both a dictionary and a linked list.

Hashtables are not inherently sorted, your best bet is to use another structure such as a SortedList or an ArrayList

Related

Order Dictionary from Keys from another Dictionary

I have two dictionaries:
Dictionary<string, Tuple<T, T>> dict1
Dictionary<Enum, Tuple<string, DateTime, DateTime>> dict2
The string value in the first item in the tuple is sometimes equal to the key in the first dictionary. I would like to sort the second dictionary by the enum value and then sort the first dictionary based on the order that dict2 has. How would I be able to do that while retaining the other keys that might be in dict1? I'm able to get as far as sorting the dictionary.
var positions = new Dictionary<Enum, string>();
//This foreach loop can be simplified by a linq expression.
foreach (var position in dict2)
{
var isFound = dict1.Any(x => x.Key == position.Value.Item1.Value);
if (isFound)
{
clubPositions.Add(position.Key, position.Value.Item1.Value);
}
}
var sortedPositions = positions.OrderByDescending(x => x.Key);
You are looking for the SortedDictionary documented on MSDN here. You will need to instantiate them as such:
var dict1 = new SortedDictionary<string, Tuple<DateTime, DateTime>>();
var dict2 = new SortedDictionary<Enum, Tuple<string, DateTime, DateTime>>();
Once you have the sorted dictionaries instances you can use LINQ to map or filter or do whatever else is desired on them. When items are added to the dictionaries they are automatically sorted based on either the ICompare<T> for the given TKey (or the default IComparer if not explicitly provided).
One downside is the fact that this sorts based on the key alone, there is no concept of sorting based on values.
The way I understand the question is not to sort the first dictionary, but to be able to iterate its elements in order defined by the second dictionary keys. If that's correct, the following should do the trick:
var orderedKeys = new HashSet<string>(dict2.OrderBy(e => e.Key).Select(e => e.Value.Item1));
var orderedEntries = orderedKeys.Where(dict1.ContainsKey)
.Select(key => new KeyValuePair<string, Tuple<T, T>>(key, dict1[key]))
.Concat(dict1.Where(e => !orderedKeys.Contains(e.Key)));
Note that it will put the entries that has no corresponding key last in the order.
You can not sort dictionary as it uses hash algorithm for constant search.
A regular dictionary cannot be sorted. You could use a SortedDictionary, it exists for this exact purpose.

Check key / value pair in List

I have list declared as
List<KeyValuePair<string, Int64>> KPList = new List<KeyValuePair<string, long>>();
I need to check if a combination of key and value already exists. I can't use dictionary since I need to have unique combination of key and value where in case a key will have multiple values but as a single pair
if(!KPList.Any(p=> p.Key ==keyp && p.Value == valuep))
What is wrong in this?
You can also use HashSet, which doesn't have values, but works as you need.
HashSet< Tuple<string, long> > KPSet = new HashSet< Tuple<string, long> >();
...
if(KPSet.Contains(p))
{
...
}
For easy-use and best performance I would like to suggest use combination of Dictionary and HashSet :
var KPDict = new Dictionary<string, HashSet<long>>();
Then it will provides you O(1)+O(1) lookup complexity and easy check of value:
if (KPDict.ContainsKey(keyp) && KPDict[keyp].Contains(valuep)) {
//do some actions
}
else{
//some logic in case keyp, valuep pair not found in KPDict
}

How to add duplicate keys into the Dictionary

I have some lines from text files that i want to add into the Dictionary.I am using Dictionary for the first time.While adding up starting lines it was Ok but suddenly i got error:
An item with the same key has already been added
Here in my code there are duplicate keys which i can not change.Here is my code in c#
Dictionary<string, string> previousLines = new Dictionary<string, string> { };
previousLines.Add(dialedno, line);
Here dialedno is the key and line is the textfile line.
Here is the code from which i am retrieving the given line based on key.
string tansferOrginExt = previousLines[dialedno];
So my concern is how to allow to add duplicate keys in Dictionary if possible and if not how can i get similar functionality.
how to allow to add duplicate keys in Dictionary
It is not possible. All keys should be unique. As Dictionary<TKey, TValue> implemented:
Every key in aDictionary<TKey, TValue> must be unique according to
the dictionary's equality comparer.
Possible solutions - you can keep collection of strings as value (i.e. use Dictionary<string, List<string>>), or (better) you can use Lookup<TKey, TValue> instead of dictionary.
how to check for duplicate keys and delete previous value from
Dictionary?
You can check if the key exists with previousLines.ContainsKey(dialedno) but if you always want to hold the last line, then just replace whatever dictionary had for the key, or add the new key if it is not in the dictionary:
previousLines[dialedno] = line;
We can Use a List of Key Value Pair
List<KeyValuePair<string, string>> myduplicateLovingDictionary= new List<KeyValuePair<string, string>>();
KeyValuePair<string,string> myItem = new KeyValuePair<string,string>(dialedno, line);
myduplicateLovingDictionary.Add(myItem);
Its not possible to add duplicate items to a Dictionary - an alternative is to use the Lookup class.
Enumerable.ToLookup Method
Creates a generic Lookup from an IEnumerable.
Example:
class Program
{
private static List<KeyValuePair<string, int>> d = new List<KeyValuePair<string, int>>();
static void Main(string[] args)
{
d.Add(new KeyValuePair<string, int>("joe", 100));
d.Add(new KeyValuePair<string, int>("joe", 200));
d.Add(new KeyValuePair<string, int>("jim", 100));
var result = d.Where(x => x.Key == "joe");
foreach(var q in result)
Console.WriteLine(q.Value );
Console.ReadLine();
}
}
List< KeyValuePair < string, string>> listKeyValPair= new List< KeyValuePair< string, string>>();
KeyValuePair< string, string> keyValue= new KeyValuePair< string, string>("KEY1", "VALUE1");
listKeyValPair.Add(keyValue);
If your question is if you can add the same key twice, the answer is No.
However if you want to just iterate through the item and then increase the count of the value for the particular Key, you can achieve that by using "TryAdd" method.
var dict = new Dictionary<int, int>();
foreach (var item in array)
{
dict.TryAdd(item, 0);
dict[item]++;
}
The same thing we are trying to achieve with if else, can be achieved with this method.``
https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentdictionary-2.tryadd?view=netframework-4.7.2

A dictionary with multiple entries with the same key [duplicate]

This question already has answers here:
C# dictionary - one key, many values
(15 answers)
Closed 8 years ago.
I need a Dictionary like object that can store multiple entries with the same key. Is this avaliable as a standard collection, or do I need to roll my own?
To clarify, I want to be able to do something like this:
var dict = new Dictionary<int, String>();
dict.Add(1, "first");
dict.Add(1, "second");
foreach(string x in dict[1])
{
Console.WriteLine(x);
}
Output:
first
second
In .NET 3.5 you can use a Lookup instead of a Dictionary.
var items = new List<KeyValuePair<int, String>>();
items.Add(new KeyValuePair<int, String>(1, "first"));
items.Add(new KeyValuePair<int, String>(1, "second"));
var lookup = items.ToLookup(kvp => kvp.Key, kvp => kvp.Value);
foreach (string x in lookup[1])
{
Console.WriteLine(x);
}
The Lookup class is immutable. If you want a mutable version you can use EditableLookup from MiscUtil.
I would recommend doing something like this:
var dict = new Dictionary<int, HashSet<string>>();
dict.Add(1, new HashSet<string>() { "first", "second" });
Dictionary<T,K> does not support such behavior and there's no collection in the base class library providing such behavior. The easiest way is to construct a composite data structure like this:
var data = new Dictionary<int, List<string>>();
As the second parameter you should use a collection which provides the qualities you are looking for, i.e. stable order ⇒ List<T>, fast access HashSet<T>, etc.
You definitely want to use NameValueCollection:
using System.Collections.Specialized;
NameValueCollection nvc = new NameValueCollection();
nvc.Add("pets", "Dog");
nvc.Add("pets", "Rabbit");
Console.WriteLine(nvc["pets"]);
//returns Dog,Rabbit
What you're looking for isn't actually a Dictionary in the traditional sense (see Associative Array).
There's no class, as far as I'm aware, that offers this in the framework (System.Linq.Lookup doesn't expose a constructor), but you could create a class yourself that implements ILookup<TKey, TElement>
You could perhaps use a Dictionary on your primary key, in which each element is a List or other collection on your secondary key. To add an item to your data structure, see if the primary key exists. If not, create a new single-item list with your Value and store it in the dictionary. If the primary key does exist, add your Value to the list that's in the dictionary.

C# - Remove a item from list of KeyValuePair

How can I remove a item from list of KeyValuePair?
If you have both the key and the value you can do the following
public static void Remove<TKey,TValue>(
this List<KeyValuePair<TKey,TValue>> list,
TKey key,
TValue value) {
return list.Remove(new KeyValuePair<TKey,TValue>(key,value));
}
This works because KeyValuePair<TKey,TValue> does not override Equality but is a struct. This means it uses the default value equality. This simply compares the values of the fields to test for equality. So you simply need to create a new KeyValuePair<TKey,TValue> instance with the same fields.
EDIT
To respond to a commenter, what value does an extension method provide here?
Justification is best seen in code.
list.Remove(new KeyValuePair<int,string>(key,value));
list.Remove(key,value);
Also in the case where either the key or value type is an anonymous type, an extension method is required.
EDIT2
Here's a sample on how to get KeyValuePair where one of the 2 has an anonymous type.
var map =
Enumerable.Range(1,10).
Select(x => new { Id = x, Value = x.ToString() }).
ToDictionary(x => x.Id);
The variable map is a Dicitonary<TKey,TValue> where TValue is an anonymous type. Enumerating the map will produce a KeyValuePair with the TValue being the same anonymous type.
Here are a few examples of removing an item from a list of KeyValuePair:
// Remove the first occurrence where you have key and value
items.Remove(new KeyValuePair<int, int>(0, 0));
// Remove the first occurrence where you have only the key
items.Remove(items.First(item => item.Key.Equals(0)));
// Remove all occurrences where you have the key
items.RemoveAll(item => item.Key.Equals(0));
EDIT
// Remove the first occurrence where you have the item
items.Remove(items[0]);
To remove all items in the list by key:
myList.RemoveAll(x => x.Key.Equals(keyToRemove));
Should be able to use the .Remove(), .RemoveAt(), or one of the other methods.
List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
KeyValuePair<string, string> kvp = list[i];
list.Remove(kvp);
or
list.Remove(list[1]);
You must obtain a reference to the object you want to remove - that's why I found the item I'm looking for and assigned to a KeyValuePair - since you're telling it to remove a specific item.
A better solution might be to use a dictionary:
Dictionary<string, string> d = new Dictionary<string, string>();
if (d.ContainsKey("somekey")) d.Remove("somekey");
This allows you to remove by the key value instead of having to deal with the list not being indexed by the key.
Edit you may not have to get a KeyValuePair reference first. Still, a dictionary is probably a better way to go.

Categories