I'm new to programming, and I created a tuple list with
var tupleList = new List<Tuple<string, string>> { };
Later on in the code, I'd like to add an element like
tupleList.Add(string1,string2);
but .Add doesn't support this somehow?
Basically, I'm going through a loop and adding to the tuple and later I want to search through the tuple for a sample string, so my second question is how would I search through tupleList.Item1 and get all the pairs that equal, for example string10? I saw an answer for dictionary values, but can I do the same for tuples?
var matches = tupleList.Where(pair => pair.Item1.Equals(string10))
.Select(pair => Item2.Key);
I don't know if that makes sense though, this was the original code:
var matches = dict.Where(pair => pair.Value == "abc")
.Select(pair => pair.Key);
List<T> does not have any specific methods for working with tuples. It works with any type T. If you want to add new item to list, you should create item of list's type T and pass it to list. Adding new tuple:
tupleList.Add(Tuple.Create(string1,string2));
For searching just filter tuples list. You should not project tuples with Select operator if you want to get them as result:
var matches = tupleList.Where(pair => pair.Item1 == string10);
NOTE: I don't like tuples for their meaningless names Item1, Item2 etc, which is hard to understand. Consider creating custom class which will have properties with descriptive names.
I'd say why do the same for tuples?
If you are using a tuple to represent a key value pair, just stick to a key value pair, which is what a dictionary contains a collection of. If you model a row with more than 2 values, I'd probably favour a strongly typed model over this, where you can be more explicit in your LINQ queries.
Related
I was asked the following question in an interview. How can I sort a Dictionary by the key, in the order which is in an array list.
So for example I have a dictionary as follows
Dictionary<string, string> stringDict = new Dictionary<string, string>();
stringDict.Add("1", "One");
stringDict.Add("7", "Seven");
stringDict.Add("6", "Six");
stringDict.Add("2", "Two");
stringDict.Add("3", "Three");
stringDict.Add("5", "Five");
stringDict.Add("4", "Four");
And an array list as follows
ArrayList stringArList = new ArrayList();
stringArList.Add("1");
stringArList.Add("2");
stringArList.Add("3");
stringArList.Add("5");
stringArList.Add("6");
stringArList.Add("7");
stringArList.Add("4");
How can I sort the dictionary in the order it is in the array list?
Well you can't sort a Dictionary per se, but you can extract the key-values pairs as a list and sort those:
IEnumerable<KeyValuePair<string, string>> pairs =
stringDict.OrderBy(kvp => stringArList.IndexOf(kvp.Key));
But there's not a way to "traverse" dictionary items in any particular order.
You could create a SortedDictionary and provide an IComparer<string>
var d = new SortedDictionary<string, string>(stringDict,
new PositionComparer(stringArList));
With the Comparer implementation as:
public class PositionComparer : IComparer<string>
{
private ArrayList Keys {get; set;}
public PositionComparer(ArrayList keys)
{
Keys = keys;
}
public int Compare(string s1, string s2)
{
return Keys.IndexOf(s1).CompareTo(Keys.IndexOf(s2));
}
}
This will produce a list of the values sorted as required.
var sortedValues = stringDict.OrderBy(pair => stringArList.IndexOf(pair.Key))
.Select(pair => pair.Value)
.ToList();
As said many times before in this question, a C# Dictionary can not be sorted. This is inherent to the implementation. As you can read here, the dictionary is implemented using a Hashtable. This means that those items don't have any ordering. You can't say "give me the first element of this dictionary". There simply is no first, second or last element. The only thing you can say about an element in a dictionary is that it has a unique identifier which determines it's location in the dictionary (with a little help from the hash function).
When you have an element in an array for example, you can say "this element is the next element" or "this element is the previous element". Each element in an array has a previous and a next. This does not hold for dictionaries.
When you insert an item into the dictionary it will generate a hash (a fairly unique number) based on the key. For example, a very simple (and bad) hash of keys consisting of names would be to take the sum of each character presented as their ASCII value in the name, and then add those together. The result is a number, say 5, then we would insert the value in a store (an array for example) on position 5. If however, at position 5 is another value, which happens to have the same hash result you have a collision. How you solve these, and how you avoid these is what hashtables are all about. See the Wiki for more information on this.
When you request your value with your key someName it will hash that value and look it up at that position.
Hashtables are not as easy as I just explained, there is a lot too it. You can read more on the Wiki.
So the answer to "Sort this dictionary" is most definitely "No can do.". However, you can convert it to a sortable data structure like a list, or whatever and then sort it.
I replied with the following answer.
var list = from arElement in stringArList.ToArray().ToList()
join dict in stringDict on arElement equals dict.Key
select dict ;
But the interviewer didn't seem to be impressed.
original_dic.OrderBy returns IOrderedEnumerable, that you convert to a new dictionary.
var ordered_dic = original_dic.OrderBy(x => x.Key).ToDictionary(x=> x.Key, x=> x.Value);
I have a function that returns a Dictionary. Key = Players, Value = Score.
Now I want to compare the scores and create a new Dictionary with the new rearanged list where the top score is on top.
Whenever I use GroupBy, it creates automatically Dictionary
so if I do something like this
Dictionary<string, int> player = playersRank.getRoundRank ().GroupBy (v => v.Value).Select(k => k.Key);
I get a Dictionary<int, <string,int>>
How can I order them by value but get Dictionary in return?
Your result collection can not be a dictionary because a dictionary is not a ordered collection. You have some options, for example you could use a List of KeyValuePair
List<KeyValuePair<string, int>> sortedScores;
sortedScores = playersRank.getRoundRank().OrderByDescending(v => v.Value).ToList();
You could use many other types too (or even create your own class), it all depends on how you plan on using this list of sorted scores after you create it. If you update your question with more details we may be able to give you better answers on what type of collection you should use.
I have tried to sort a Dictionary object by value which is generic.
Here is my code
Dictionary<string, ReportModel> sortedDic = new Dictionary<string, ReportModel>();
Dictionary<string, ReportModel> rDic = new Dictionary<string, ReportModel>();
var ordered = sortedDic.OrderByDescending(x => x.Value.totalPurchase);
foreach (var item in ordered)
{
rDic.Add(item.Key, item.Value);
}
The variable, ordered, just has the same order like sortedDic.
What is wrong with this?
Any idea?
This happens because Dictionary is generally an unordered container*. When you put the data into rDic, it becomes unordered again.
To retain the desired order, you need to put the results into a container that explicitly keeps the ordering that you supply. For example, you could use a list of KeyValuePair<string,ReportModel>, like this:
IList<KeyValuePair<string,ReportModel>> ordered = sortedDic
.OrderByDescending(x => x.Value.totalPurchase)
.ToList();
* Due to the way the Dictionary<K,V> is implemented by Microsoft, it happens to retain the insertion order, but that is incidental and undocumented, so it may change in the future versions, and should not be relied upon.
When adding the items back to the dictionary, it would not keep their order.
You can either:
Use the following implementation.
Use a list in the below form.
IEnumrable> lst=
sortedDic.OrderByDescending(x => x.Value.totalPurchase).ToArray();
[EDIT] If you don't mind the key changing then you can use SortedDictionary<,>.
I want to build an Dictonary like this :
Dictionary<String, ArrayList> myDic = new Dictionary<String, ArrayList>();
in the end i want a structure like :
["blabla"] => array(1,2,3)
["foo"] => array(1,4,6,8)
.......
to build this i run in a loop and in every loop build some strings ,
first question :
how to check every time if this string exists
in the dictionary , if its not exists open a new entry in dictionary with one element in the array list, if exists only add another element to the array list
and another question:
how can i sort this dictionary according to number of elements in the array list(In descending order) like :
["foo"] => array(1,4,6,2,8)
["bar"] => array(4,6,2,8)
["bla"] => array(1,2,3)
["blo"] => array(1,2)
.......
thanks !
Use the right tool for the job. The data structure you want is called a "multi-dictionary" - that is a dictionary that maps from a key to a sequence of values, rather than from a key to a unique value.
The PowerCollections codebase contains an implementation of MultiDictionary that probably does what you want. I would use it rather than writing your own.
To sort the dictionary into a sequence of key/sequence pairs ordered by the length of the sequence, I would use a LINQ query with an "order by" clause. That seems like the easiest way to do it.
Instead of ArrayList you should use an array or List<T>. Assuming you have a Dictionary<string, int> called source this should work:
var items = source
.GroupBy(kvp => kvp.Key)
.Select(grp => new { Key = grp.Key, Items = grp.Select(kvp => kvp.Value).ToArray() })
.OrderByDescending(i => i.Items.Length);
To explain, Dictionary<TKey, TValue> implements IEnumerable<KeyValuePair<TKey, TValue>> so can be considered a sequence of key-value pairs. Group by groups the pairs by key and then Select creates a sequence of an anonymous type which contains the key and associated values in a Key and Items property respectively. This sequence is then ordered by the number of items in the Items array of each object.
If you want to order them by the length of the created array, you can't use a dictionary since they are not ordered.
To check if a key exists in a dictionary and use the value if it does, you can use TryGetValue:
ArrayList array;
if(!myDic.TryGetValue("blabla", out array))
{
array = new ArrayList();
myDic["blabla"] = array;
}
array.Add(42);
Would something like this work:
if (myDic.ContainsKey(myString))
myDic[myString].Add(myNumber);
else
myDic.Add(myString, new ArrayList(new int[] {myNumber}));
I have a Hashtable that maps strings to ints. Strings are unique, but several may be mapped to the same integer.
My naive approach was to simply invert the Hashtable to a SortedList that is indexed by the Hashtable's values, but the problem is that you get a clash as soon as two of the Hashtable's strings map to the same value.
What is the most efficient way to list my entire Hashtable (keys and values) ordered by the values? (Where two values are the same, I don't care about their ordering.)
Using Linq:
hashtable.Cast<DictionaryEntry>().OrderBy(entry => entry.Value).ToList()
You said you wanted the most efficient method. The following code is the best I could find.
Hashtable hashtable = GetYourHashtable();
var result = new List<DictionaryEntry>(hashtable.Count);
foreach (DictionaryEntry entry in hashtable)
{
result.Add(entry);
}
result.Sort(
(x, y) =>
{
IComparable comparable = x.Value as IComparable;
if (comparable != null)
{
return comparable.CompareTo(y.Value);
}
return 0;
});
foreach (DictionaryEntry entry in result)
{
Console.WriteLine(entry.Key.ToString() + ":" + entry.Value.ToString());
}
I experimented with various different approaches using Linq, but the above method was about 25-50% faster.
Maybe this could work:
myhashtable.Keys.Select(k => new List<string, int>() {k, myhashtable[k]})
.OrderBy(item => item[1]);
This should give you a list of lists, with the nested lists containing exactly two elements, the key and the value. Sorted by the value (second element).
I'm not quite sure if the Hashtable has a KeyValuePair<K, V> type... something like this could also work:
myhashtable.Items.OrderBy(kvp => kvp.Value);
The immediate way that springs to mind is along the lines of what you have except that you have a SortedList (or similar) that uses the original values (ie the integers) as keys and as values has a list of the original keys (ie the strings if I understand correctly). There is a bit more faff involved in adding values (since you need to check if they exist and add them to the list if so or create a new list otherwise). There may be better methods but this is the one that immediately springs to mind...