Enumerable.ElementAt vs foreach - c#

I have a dictionary which I need to keep updated with incoming data, after parsing the incoming data I have to check if there are any entries in the dictionary which are not present in the incoming data (incoming data when parsed is a list and I need to map it with the dictionary entries).
To avoid multiple loops to removed the entries, I ran a decrementing for loop for dictionary count, then I fetch the dictionary key of the index using ElementAt, then check if the entry is present in the incoming data if not then I remove that entry from the list. I did this because running the foreach loop on the dictionary keys and removing from it will raise and exception as the dictionary keys collection would be modified.
I wanted to understand that doing this will there be any impact on execution time. I want to understand what is the order of ElementAt operation.

ElementAt is useful if you need to provide indexing semantics and cannot guarantee that indexing semantics will be available in the underlying enumeration. It does use O(1) indexing when the enumeration acted upon is an IList<T> (which includes List and arrays), but otherwise is O(n)*, which makes it being used in a sequence over everything go from the O(n) operation it would be with a list to O(n * n).
If however you got a copy of the keys with dict.Keys.ToList() then you could safely foreach through that, as it won't be changed by changes to your dictionary.
What isn't clear is why you don't just replace the old dictionary with the new one, which would be considerably faster again (simple reference assignment).
*Update: In the .NET Core version of linq there are a greater range of cases where ElementAt() is O(1) such as the results of a Select() done on an IList<T>. Also OrderBy(…).ElementAt(…) is now O(n) rather than O(n log n) as the combined sequence is turned into a quick-select rather than a quicksort followed by an iteration.

Use "mark then remove" trick as a workaround for inability to modify collection while iterating.
var dict = new Dictionary<int, string>
{
{3, "kuku" },
{1, "zOl"}
};
var newKeys = new List<int> { 1, 2, 4 };
var toRemove = dict.Keys.Except(newKeys).ToList();
foreach (var k in toRemove)
dict.Remove(k);

ElementAt() does use the enumerator as pointed out, so if you want fastest index access you should use an array. Of course, that comes at the price of a fixed length, but if the size of the array is not constantly changing, it is feasible that Array.Resize() might be the way to go.

Except() seems like it would work here:
Dictionary<int, string> dict = new Dictionary<int, string>
{
{3, "kuku" },
{1, "zOl"}
};
IEnumerable<int> data = new List<int> { 1, 2, 4 };
IEnumerable<int> toRemove = dict.Keys.Except(data);
foreach(var x in toRemove)
dict.Remove(x);

I think that ElementAt() uses the enumerator to get to the required element.
It will be the same as:
object returnedElement = null;
int i = 0;
foreach (var obj in dictionary.Keys)
{
if (i++ == at)
{
returnedElement = obj;
break;
}
}

You can get a Dictionary of the matching entries in target (Dictionary) and source (List) as follows:
using System;
using System.Collections.Generic;
using System.Linq;
Dictionary<string, string> target = new Dictionary<string, string>();
List<string> source = new List<string>();
target.Add("a", "this is a");
target.Add("b", "this is b");
source.Add("a");
source.Add("c");
target = Enumerable.Select(target, n => n.Key).
Where(n => source.Contains(n)).ToDictionary(n => n, k => target[k]);
It's not clear to me if you want to include new entries from the List into the Dictionary - if so, I am not sure what the new entry values would be if you only have a List of new incoming data.

Related

Sort the dictionary after the value after the key

I have a problem with sorting dictionary:
SortedDictionary<string, List<int>> mySortedDictionary;
I want to create new Dictionary<string,List<int>> with data from mySortedDictionary, which is sorted by value(exactly by the number of items list in other words List.Count) ascending and while the lists.Count are the same, the keys are sorted alphabetically ascending. Can anyone drop me an idea how to do this?
mySortedDictionary.Add("orange", List<2,9>) //List.Count = 2
mySortedDictionary.Add("money", List<2,4,8,9>) //4
mySortedDictionary.Add("monkey", List<2,4,9>) //3
mySortedDictionary.Add("hokey", List<2,5,9>) //3
//result: order in new sorted Dictionary//
"orange", List<2,9>
"hokey", List<2,5,9>
"monkey", List<2,4,9>
"money", List<2,4,8,9>
Thank you in advance for your help!!!
SortedDictionary stores data by sorting over key and this is intrinsic to it i.e. cannot be replaced by a custom sorting. So if you want a Dictionary like interface, you will have to build a custom Data structure.
If the reading the data in sorted order operation will happen frequently, you need to devise a mechanism to store the sorted data (cache the sorted data and original data separately) or store the data in a sorted manner. Remember that the Value in the dictionary might change during the life-time of the data structure, so you might have to re-order your data. This might not be a trivial exercise.
But if you really want a Dictionary interface in general, but sometimes need the data to be obtained in specific sequence, then the below approach will be helpful.
Store the data in a regular Dictionary. To obtain the Dictionary data in sorted order, you can provide a method like below.
IOrderedEnumerable<KeyValuePair<string, List<int>>> GetSortedData() {
return mySortedDictionary.OrderBy(item => item.Value.Count).ThenBy(item => item.Key);
}
I believe SortedDictionary types only sort on the key part (which was part of your requirement), but you can also use the OrderBy() method to specify a custom ordering. Note that this does not change the order of the elements in the dictionary, instead it returns an IOrderedEnumerable with the specified order. So if you want to change the order, you would have to re-assign the dictionary to the result of the OrderBy call. If that's what you're trying to do, maybe this will help:
var mySortedDictionary = new SortedDictionary<string, List<int>>
{
{"orange", new List<int> {2, 9}},
{"money", new List<int> {2, 4, 8, 9}},
{"monkey", new List<int> {2, 4, 9}},
{"hokey", new List<int> {2, 5, 9}}
};
foreach (var item in mySortedDictionary.OrderBy(item => item.Value.Count))
{
Console.WriteLine($"{item.Key} {string.Join(", ", item.Value)}");
}
Output:
To keep this order in the dictionary, you would have to do a reassignment, like so:
mySortedDictionary = mySortedDictionary.OrderBy(item => item.Value.Count);
You need a custom class to implement IComparable so the sort is as you want to use a SortedDictionary.
public class ncKey : IComparable {
public int count;
public string name;
public int CompareTo(object other) {
var b = other as ncKey;
var ans1 = count.CompareTo(b?.count);
return (ans1 == 0) ? name.CompareTo(b?.name) : ans1;
}
}
Now you can use the class to have a properly sorted dictionary:
var newSD = new SortedDictionary<ncKey, List<int>>();
foreach (var kv in origSD)
newSD.Add(new ncKey { count = kv.Value.Count(), name = kv.Key }, kv.Value);
Of course, I wonder if you really wouldn't be better off with a SortedList and why you are using dictionaries at all.

How to get Distinct keys of all child dictionary elements of all parent dictionary values

I have a dictionary like this...
Dictionary<string, Dictionary<string, double>>
How to get the list of all Distinct or unique child dictionary keys from all dictionaries of all parent dictionary values (parent dictionary values is nothing but child dictionaries)?
which is the fastest way of doing this in C#?
It's really easy using LINQ:
var result = myDict.Values.SelectMany(x => x.Keys)
.Concat(myDict.Keys)
.Distinct()
.ToList();
but even without LINQ it's super easy when you use HashSet<string>:
var set = new HashSet<string>();
foreach(var outerItem in myDict)
{
set.Add(outerItem.Key);
foreach(var innerKey in item.Value.Keys)
{
set.Add(innerKey);
}
}
HashSet<T> will only keep distinct items, so adding the same string twice won't make any difference.
PS. Next time you should try writing the code first, and ask question when you run into issue you can't overcome by yourself. Stack Overflow is not 'I want code, give me code' kind of site.
Then you need to call SelectMany() on Values property of your dictionary and then use Distinct() to get distinct elements from a sequence by using the default equality comparer.
var res = myDict.Values.SelectMany(x => x.Keys).Distinct().ToList();
This code creates a Dictionary with string keys and double values.
Dictionary<string, double> d = new Dictionary<string, double>()
{
};
// Store keys in a List
List<string> list = new List<string>(d.Keys);
// Loop through list
foreach (string k in list)
{
//From here you can choose distinct key
}
If I'm reading this right:
IEnumerable<string> uniqueChildKeys = dictOfDicts
.SelectMany(d => d.Value.Keys)
.Distinct();

C# data structure: What type of collection should I use?

For each item in the collection, I need to have a short string and a few int16 fields. I want to iterate through the collection using the string field (meaning I don't want to use numeric index to iterate).
The collection is at most about 10 items. Thanks for any suggestions.
I think Dictionary<string, List<int>> should work for you needs.
Dictionary<string, List<int>> dictionary = new Dictionary<string, List<int>>();
dictionary.Add("key", new List<int>{1,2,3,4});
...
If you use .NET 4 and the "few int16" are always the same number of values you might also want to consider the Tuple class as value in the dictionary:
var map = new Dictionary<string, Tuple<Int16, Int16, Int16>>();
map["Foo"] = Tuple.Create(1, 2, 3);
var values = map["Foo"];
Console.WriteLine("{0} {1} {2}", value.Item1, value.Item2, value.Item3);
I would use a Dictionary so you can index into it using an arbitrary key - string, in your case.
If you mean iterate as looping thru; then it really does not matter because all collections support foreach:
foreach (var item in collection) { ... }
However, if you mean iterate as indexing, then a Dictionary should do the job.
class SomeFields { public int a; public int b; ... }
var collection = new Dictionary<string, SomeFields>();
collection.Add("name", new SomeFields() { a = 1, b = 2 });
var fields = collection["name"];
If the items in the collection is small "10 items or less" then better for performance to use ListDictionary, If you are not sure about the elements count or if the element count maybe increase in the future then use HaybridDictionary.
Note that HybridDictionary mechanism is to use internally a ListDictionary while the collection is small, and then switching to a Hashtable when the collection gets large.

The order of elements in Dictionary

My question is about enumerating Dictionary elements
// Dictionary definition
private Dictionary<string, string> _Dictionary = new Dictionary<string, string>();
// add values using add
_Dictionary.Add("orange", "1");
_Dictionary.Add("apple", "4");
_Dictionary.Add("cucumber", "6");
// add values using []
_Dictionary["banana"] = 7;
_Dictionary["pineapple"] = 7;
// Now lets see how elements are returned by IEnumerator
foreach (KeyValuePair<string, string> kvp in _Dictionary)
{
Trace.Write(String.Format("{0}={1}", kvp.Key, kvp.Value));
}
In what order will be the elements enumerated? Can I force the order to be alphabetical?
The order of elements in a dictionary is non-deterministic. The notion of order simply is not defined for hashtables. So don't rely on enumerating in the same order as elements were added to the dictionary. That's not guaranteed.
Quote from the doc:
For purposes of enumeration, each item in the dictionary is treated as a KeyValuePair<TKey, TValue> structure representing a value and its key. The order in which the items are returned is undefined.
You can always use SortedDictionary for that. Note that the dictionary is ordered by Key, by default, unless a comparer has been specified.
I'm skeptic regarding the use of OrderedDictionary for what you want since documentation says that:
The elements of an OrderedDictionary are not sorted by the key, unlike
the elements of a SortedDictionary class.
If you want the elements ordered, use a SortedDictionary. An ordinary hastable/dictionary is ordered only in some sense of the storage layout.
The items will be returned in the order that they happen to be stored physically in the dictionary, which depends on the hash code and the order the items were added. Thus the order will seem random, and as implementations change, you should never depend on the order staying the same.
You can order the items when enumerating them:
foreach (KeyValuePair<string, string> kvp in _Dictionary.OrderBy(k => k.Value)) {
...
}
In framework 2.0 you would first have to put the items in a list in order to sort them:
List<KeyValuePair<string, string>> items = new List<KeyValuePair<string, string>>(_Dictionary);
items.Sort(delegate(KeyValuePair<string, string> x, KeyValuePair<string, string> y) { return x.Value.CompareTo(y.Value); });
foreach (KeyValuePair<string,string> kvp in items) {
...
}
For an OrderedDictionary:
var _OrderedDictionary = new System.Collections.Specialized.OrderedDictionary();
_OrderedDictionary.Add("testKey1", "testValue1");
_OrderedDictionary.Add("testKey2", "testValue2");
_OrderedDictionary.Add("testKey3", "testValue3");
var k = _OrderedDictionary.Keys.GetEnumerator();
var v = _OrderedDictionary.Values.GetEnumerator();
while (k.MoveNext() && v.MoveNext()) {
var key = k.Current; var value = v.Current;
}
Items are returned in the order that they are added.
Associative arrays (aka, hash tables) are unordered, which means that the elements can be ordered in any way imaginable.
HOWEVER, you could fetch the array keys (only the keys), order that alphabetically (via a sort function) and then work on that.
I cannot give you a C# sample because I don't know the language, but this should be enough for you to go on yourself.

How do you sort a dictionary by value?

I often have to sort a dictionary (consisting of keys & values) by value. For example, I have a hash of words and respective frequencies that I want to order by frequency.
There is a SortedList which is good for a single value (say frequency), that I want to map back to the word.
SortedDictionary orders by key, not value. Some resort to a custom class, but is there a cleaner way?
Use LINQ:
Dictionary<string, int> myDict = new Dictionary<string, int>();
myDict.Add("one", 1);
myDict.Add("four", 4);
myDict.Add("two", 2);
myDict.Add("three", 3);
var sortedDict = from entry in myDict orderby entry.Value ascending select entry;
This would also allow for great flexibility in that you can select the top 10, 20 10%, etc. Or if you are using your word frequency index for type-ahead, you could also include StartsWith clause as well.
Use:
using System.Linq.Enumerable;
...
List<KeyValuePair<string, string>> myList = aDictionary.ToList();
myList.Sort(
delegate(KeyValuePair<string, string> pair1,
KeyValuePair<string, string> pair2)
{
return pair1.Value.CompareTo(pair2.Value);
}
);
Since you're targeting .NET 2.0 or above, you can simplify this into lambda syntax -- it's equivalent, but shorter. If you're targeting .NET 2.0 you can only use this syntax if you're using the compiler from Visual Studio 2008 (or above).
var myList = aDictionary.ToList();
myList.Sort((pair1,pair2) => pair1.Value.CompareTo(pair2.Value));
You could use:
var ordered = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
You can sort a Dictionary by value and save it back to itself (so that when you foreach over it the values come out in order):
dict = dict.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
Sure, it may not be correct, but it works. Hyrum's Law means that this will very likely continue to work.
Looking around, and using some C# 3.0 features we can do this:
foreach (KeyValuePair<string,int> item in keywordCounts.OrderBy(key=> key.Value))
{
// do something with item.Key and item.Value
}
This is the cleanest way I've seen and is similar to the Ruby way of handling hashes.
On a high level, you have no other choice than to walk through the whole Dictionary and look at each value.
Maybe this helps:
http://bytes.com/forum/thread563638.html
Copy/Pasting from John Timney:
Dictionary<string, string> s = new Dictionary<string, string>();
s.Add("1", "a Item");
s.Add("2", "c Item");
s.Add("3", "b Item");
List<KeyValuePair<string, string>> myList = new List<KeyValuePair<string, string>>(s);
myList.Sort(
delegate(KeyValuePair<string, string> firstPair,
KeyValuePair<string, string> nextPair)
{
return firstPair.Value.CompareTo(nextPair.Value);
}
);
You'd never be able to sort a dictionary anyway. They are not actually ordered. The guarantees for a dictionary are that the key and value collections are iterable, and values can be retrieved by index or key, but there is no guarantee of any particular order. Hence you would need to get the name value pair into a list.
You do not sort entries in the Dictionary. Dictionary class in .NET is implemented as a hashtable - this data structure is not sortable by definition.
If you need to be able to iterate over your collection (by key) - you need to use SortedDictionary, which is implemented as a Binary Search Tree.
In your case, however the source structure is irrelevant, because it is sorted by a different field. You would still need to sort it by frequency and put it in a new collection sorted by the relevant field (frequency). So in this collection the frequencies are keys and words are values. Since many words can have the same frequency (and you are going to use it as a key) you cannot use neither Dictionary nor SortedDictionary (they require unique keys). This leaves you with a SortedList.
I don't understand why you insist on maintaining a link to the original item in your main/first dictionary.
If the objects in your collection had a more complex structure (more fields) and you needed to be able to efficiently access/sort them using several different fields as keys - You would probably need a custom data structure that would consist of the main storage that supports O(1) insertion and removal (LinkedList) and several indexing structures - Dictionaries/SortedDictionaries/SortedLists. These indexes would use one of the fields from your complex class as a key and a pointer/reference to the LinkedListNode in the LinkedList as a value.
You would need to coordinate insertions and removals to keep your indexes in sync with the main collection (LinkedList) and removals would be pretty expensive I'd think.
This is similar to how database indexes work - they are fantastic for lookups but they become a burden when you need to perform many insetions and deletions.
All of the above is only justified if you are going to do some look-up heavy processing. If you only need to output them once sorted by frequency then you could just produce a list of (anonymous) tuples:
var dict = new SortedDictionary<string, int>();
// ToDo: populate dict
var output = dict.OrderBy(e => e.Value).Select(e => new {frequency = e.Value, word = e.Key}).ToList();
foreach (var entry in output)
{
Console.WriteLine("frequency:{0}, word: {1}",entry.frequency,entry.word);
}
You could use:
Dictionary<string, string> dic= new Dictionary<string, string>();
var ordered = dic.OrderBy(x => x.Value);
return ordered.ToDictionary(t => t.Key, t => t.Value);
Or for fun you could use some LINQ extension goodness:
var dictionary = new Dictionary<string, int> { { "c", 3 }, { "a", 1 }, { "b", 2 } };
dictionary.OrderBy(x => x.Value)
.ForEach(x => Console.WriteLine("{0}={1}", x.Key,x.Value));
Sorting a SortedDictionary list to bind into a ListView control using VB.NET:
Dim MyDictionary As SortedDictionary(Of String, MyDictionaryEntry)
MyDictionaryListView.ItemsSource = MyDictionary.Values.OrderByDescending(Function(entry) entry.MyValue)
Public Class MyDictionaryEntry ' Need Property for GridViewColumn DisplayMemberBinding
Public Property MyString As String
Public Property MyValue As Integer
End Class
XAML:
<ListView Name="MyDictionaryListView">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Path=MyString}" Header="MyStringColumnName"></GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Path=MyValue}" Header="MyValueColumnName"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The other answers are good, if all you want is to have a "temporary" list sorted by Value. However, if you want to have a dictionary sorted by Key that automatically synchronizes with another dictionary that is sorted by Value, you could use the Bijection<K1, K2> class.
Bijection<K1, K2> allows you to initialize the collection with two existing dictionaries, so if you want one of them to be unsorted, and you want the other one to be sorted, you could create your bijection with code like
var dict = new Bijection<Key, Value>(new Dictionary<Key,Value>(),
new SortedDictionary<Value,Key>());
You can use dict like any normal dictionary (it implements IDictionary<K, V>), and then call dict.Inverse to get the "inverse" dictionary which is sorted by Value.
Bijection<K1, K2> is part of Loyc.Collections.dll, but if you want, you could simply copy the source code into your own project.
Note: In case there are multiple keys with the same value, you can't use Bijection, but you could manually synchronize between an ordinary Dictionary<Key,Value> and a BMultiMap<Value,Key>.
Actually in C#, dictionaries don't have sort() methods.
As you are more interested in sort by values,
you can't get values until you provide them key.
In short, you need to iterate through them using LINQ's OrderBy(),
var items = new Dictionary<string, int>();
items.Add("cat", 0);
items.Add("dog", 20);
items.Add("bear", 100);
items.Add("lion", 50);
// Call OrderBy() method here on each item and provide them the IDs.
foreach (var item in items.OrderBy(k => k.Key))
{
Console.WriteLine(item);// items are in sorted order
}
You can do one trick:
var sortedDictByOrder = items.OrderBy(v => v.Value);
or:
var sortedKeys = from pair in dictName
orderby pair.Value ascending
select pair;
It also depends on what kind of values you are storing: single (like string, int) or multiple (like List, Array, user defined class).
If it's single you can make list of it and then apply sort.
If it's user defined class, then that class must implement IComparable, ClassName: IComparable<ClassName> and override compareTo(ClassName c) as they are more faster and more object oriented than LINQ.
Required namespace : using System.Linq;
Dictionary<string, int> counts = new Dictionary<string, int>();
counts.Add("one", 1);
counts.Add("four", 4);
counts.Add("two", 2);
counts.Add("three", 3);
Order by desc :
foreach (KeyValuePair<string, int> kvp in counts.OrderByDescending(key => key.Value))
{
// some processing logic for each item if you want.
}
Order by Asc :
foreach (KeyValuePair<string, int> kvp in counts.OrderBy(key => key.Value))
{
// some processing logic for each item if you want.
}
Suppose we have a dictionary as:
Dictionary<int, int> dict = new Dictionary<int, int>();
dict.Add(21,1041);
dict.Add(213, 1021);
dict.Add(45, 1081);
dict.Add(54, 1091);
dict.Add(3425, 1061);
dict.Add(768, 1011);
You can use temporary dictionary to store values as:
Dictionary<int, int> dctTemp = new Dictionary<int, int>();
foreach (KeyValuePair<int, int> pair in dict.OrderBy(key => key.Value))
{
dctTemp.Add(pair.Key, pair.Value);
}
The easiest way to get a sorted Dictionary is to use the built in SortedDictionary class:
//Sorts sections according to the key value stored on "sections" unsorted dictionary, which is passed as a constructor argument
System.Collections.Generic.SortedDictionary<int, string> sortedSections = null;
if (sections != null)
{
sortedSections = new SortedDictionary<int, string>(sections);
}
sortedSections will contain the sorted version of sections
Sort and print:
var items = from pair in players_Dic
orderby pair.Value descending
select pair;
// Display results.
foreach (KeyValuePair<string, int> pair in items)
{
Debug.Log(pair.Key + " - " + pair.Value);
}
Change descending to acending to change sort order
A dictionary by definition is an unordered associative structure that contains only values and keys in a hashable way. In other words has not a previsible way to orderer a dictionary.
For reference read this article from python language.
Link
python data structures
Best way:
var list = dict.Values.OrderByDescending(x => x).ToList();
var sortedData = dict.OrderBy(x => list.IndexOf(x.Value));
The following code snippet sorts a Dictionary by values.
The code first creates a dictionary and then uses OrderBy method to sort the items.
public void SortDictionary()
{
// Create a dictionary with string key and Int16 value pair
Dictionary<string, Int16> AuthorList = new Dictionary<string, Int16>();
AuthorList.Add("Mahesh Chand", 35);
AuthorList.Add("Mike Gold", 25);
AuthorList.Add("Praveen Kumar", 29);
AuthorList.Add("Raj Beniwal", 21);
AuthorList.Add("Dinesh Beniwal", 84);
// Sorted by Value
Console.WriteLine("Sorted by Value");
Console.WriteLine("=============");
foreach (KeyValuePair<string, Int16> author in AuthorList.OrderBy(key => key.Value))
{
Console.WriteLine("Key: {0}, Value: {1}", author.Key, author.Value);
}
}
You can sort the Dictionary by value and get the result in dictionary using the code below:
Dictionary <<string, string>> ShareUserNewCopy =
ShareUserCopy.OrderBy(x => x.Value).ToDictionary(pair => pair.Key,
pair => pair.Value);
Given you have a dictionary you can sort them directly on values using below one liner:
var x = (from c in dict orderby c.Value.Order ascending select c).ToDictionary(c => c.Key, c=>c.Value);

Categories

Resources