C# sort dictionary list except first pair - c#

I am trying to do a sort on dictionary
class Program {
static void Main()
{
// Example dictionary.
var dictionary = new Dictionary<string, int>(5);
dictionary.Add("cat", 3);
dictionary.Add("dog", 1);
dictionary.Add("mouse", 0);
dictionary.Add("elephant", 2);
dictionary.Add("bird", 4);
var items = from pair in dictionary
orderby pair.Value ascending
select pair;
// Display results.
foreach (KeyValuePair<string, int> pair in items)
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
items = from pair in dictionary
orderby pair.Value descending
select pair;
} }
The result is
mouse
dog
elephant
cat
bird
But I need to exclude the first pair to sort the rest and to get this result
cat
mouse
dog
elephant
bird
Can I do anything from here?
var items = from pair in dictionary
orderby pair.Value ascending
select pair;

I would suggest using Linq
var result = dictionary
.Take(1) // Take first element
.Concat(dictionary // Skip first element and sort the rest on value.
.Skip(1)
.OrderBy(o=>o.Value))
.Select(x=>x.Key);
Output
cat ,
mouse ,
dog ,
elephant ,
bird
Check this Demo

dictionary.Take(1).Concat(dictionary.Skip(1).OrderBy({ logic }))
You get the idea I think

var firstItems = dictionary.Take(1);
var sortItems = from pair in dictionary.Skip(1)
orderby pair.Value ascending
select pair;
var items = firstItems.Concat(sortItems);
Beware that Dictionary does not guarantee orders.
According its implementation, orders will be messed up once after item removal.
exclude the first pair
I would suggest not to note your item by orders.

Try something like this
var result = YourList.OrderBy(mc => mc.SomePropToSortOn)
.ToDictionary(mc => mc.Key.ToString(),
mc => mc.Value.ToString(),
StringComparer.OrdinalIgnoreCase);

You can use LINQ .OrderBy:
dictionary.OrderBy(t => t.Value).ToDictionary(t => t.Key, t=> t.Value);

You can try to use this code:
var first = dictionary.Take(1);
var orderedRest = dictionary.Skip(1).OrderBy(p => p.Value);
var items = first.Union(orderedRest);
I already mentioniod that I think that a Dictionary is not the right collection type for this. In my opinion you should use List<KeyValuePair<string, int>>. The above code works with the list, too.

Related

How do I access things returned by GroupBy

Ridiculously simple question that for the life of me I cant figure out. How do I 'get' at the values returned by GroupBy?
Take simple example below. I want to print out the first value that occurs more than once. Looking at the output in the watch window (image below) it sort of suggests that list3[0][0] might get at "one". But it gives me an error.
Note, I'm looking for the general solution - ie understanding what GroupBy returns.
Also, I would like to use the watch window to help me figure out for my self how I would access variables (as I find much of MSDN reference incomprehensible) - is this possible?
var list1 = new List<String>() {
"one", "two", "three", "one", "two"};
var list3 = list1
.GroupBy(x => x)
.Where(x => x.Count() > 1)
.ToList();
Console.WriteLine("list3[0][0]=" + list3[0][0]); //error
While the VS debugger shows you an "index" number because the underlying type is a collection, the grouping is exposed as an IGrouping<T> that does not have an indexer. If you just want the first item in the first group do:
Console.WriteLine("list3[0][0] =" + list3.First().First());
If you want to see all if the items you cam loop through the groupings:
int gi = 0, ii = 0;
foreach(var g in list3)
{
foreach(item i in g)
{
Console.WriteLine("list3[{0}][{1}] = {2}", gi, ii, i);
ii++;
}
gi++;
}
You are looking for the .Key property, as GroupBy returns an IEnumerable containing IGrouping elements.
If you look at the documentation of GroupBy you'll see it returns a IEnumerable<IGrouping<TKey, TSource>>.
IGrouping<TKey,TSource> has a single property Key and itself inherits IEnumerable<TElement>.
So you can enumerate over the list of items returned from a call to GroupBy and each element will have a Key property (which is whatever you grouped by) as well as enumerate each item (which will be the list of items grouped together)
Hopefully this demonstrates a bit clearer. Given a class:
public class Person
{
public string Name{get;set;}
public int Age{get;set;}
}
And a list:
var people = new List<Person>{
new Person{Name="Jamie",Age=35},
new Person{Name="Bob",Age=45},
new Person{Name="Fred",Age=35},
};
Grouping and enumerating as follows:
var groupedByAge = people.GroupBy(x => x.Age);
foreach(var item in groupedByAge)
{
Console.WriteLine("Age:{0}", item.Key);
foreach(var person in item)
{
Console.WriteLine("{0}",person.Name);
}
}
Gives this output:
Age:35
Jamie
Fred
Age:45
Bob
Live example: http://rextester.com/OWPR50756
GroupBy return an IEnumerable<IGrouping<TKey, TSource>> where each IGrouping<TKey, TElement> object contains a sequence of objects and a key it's not a Multidimensional Array which can be accessed by index [][].
To access the first element try this
static void Main(string[] args)
{
var list1 = new List<String>() {
"one", "two", "three", "one", "two"};
var list3 = list1
.GroupBy(x => x)
.Where(x => x.Count() > 1)
.ToList();
Console.WriteLine("list3[0][0]=" + list3[0].ToList()[0].ToString());
//OR Console.WriteLine("list3[0][0]=" + list3[0].First());
}

How to get values out of IGrouping?

I have applied IGrouping<> over a list - here's what it looks like:
IEnumerable<IGrouping<TierRequest,PingtreeNode>> Tiers
{
get { return ActiveNodes.GroupBy(x => new TierRequest(x.TierID, x.TierTimeout, x.TierMaxRequests)); }
}
Later in my code I iterate over Tiers. Its simple to get the key data using the Key element, but how do I get the IEnumerable<PingtreeNode> that forms the value part?
Thanks in advance
Tiers.Select(group => group.Select(element => ...));
in foreach you can get values like this
foreach(var group in tiers)
{
TierRequest key = group.Key;
PingtreeNode[] values = group.ToArray();
}
The group itself implements IEnumerable<T> and can be iterated over, or used with linq methods.
var firstGroup = Tiers.First();
foreach(var item in firstGroup)
{
item.DoSomething();
}
// or using linq:
firstGroup.Select(item => item.ToString());
// or if you want to iterate over all items at once (kind of unwinds
// the grouping):
var itemNames = Tiers.SelectMany(g => g.ToString()).ToList();

How to get first object out from List<Object> using Linq

I have below code in c# 4.0.
//Dictionary object with Key as string and Value as List of Component type object
Dictionary<String, List<Component>> dic = new Dictionary<String, List<Component>>();
//Here I am trying to do the loping for List<Component>
foreach (List<Component> lstComp in dic.Values.ToList())
{
// Below I am trying to get first component from the lstComp object.
// Can we achieve same thing using LINQ?
// Which one will give more performance as well as good object handling?
Component depCountry = lstComp[0].ComponentValue("Dep");
}
Try:
var firstElement = lstComp.First();
You can also use FirstOrDefault() just in case lstComp does not contain any items.
http://msdn.microsoft.com/en-gb/library/bb340482(v=vs.100).aspx
Edit:
To get the Component Value:
var firstElement = lstComp.First().ComponentValue("Dep");
This would assume there is an element in lstComp. An alternative and safer way would be...
var firstOrDefault = lstComp.FirstOrDefault();
if (firstOrDefault != null)
{
var firstComponentValue = firstOrDefault.ComponentValue("Dep");
}
[0] or .First() will give you the same performance whatever happens.
But your Dictionary could contains IEnumerable<Component> instead of List<Component>, and then you cant use the [] operator. That is where the difference is huge.
So for your example, it doesn't really matters, but for this code, you have no choice to use First():
var dic = new Dictionary<String, IEnumerable<Component>>();
foreach (var components in dic.Values)
{
// you can't use [0] because components is an IEnumerable<Component>
var firstComponent = components.First(); // be aware that it will throw an exception if components is empty.
var depCountry = firstComponent.ComponentValue("Dep");
}
You also can use this:
var firstOrDefault = lstComp.FirstOrDefault();
if(firstOrDefault != null)
{
//doSmth
}
for the linq expression you can use like this :
List<int> list = new List<int>() {1,2,3 };
var result = (from l in list
select l).FirstOrDefault();
for the lambda expression you can use like this
List list = new List() { 1, 2, 3 };
int x = list.FirstOrDefault();
You can do
Component depCountry = lstComp
.Select(x => x.ComponentValue("Dep"))
.FirstOrDefault();
Alternatively if you are wanting this for the entire dictionary of values, you can even tie it back to the key
var newDictionary = dic.Select(x => new
{
Key = x.Key,
Value = x.Value.Select( y =>
{
depCountry = y.ComponentValue("Dep")
}).FirstOrDefault()
}
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, x => x.Value());
This will give you a new dictionary. You can access the values
var myTest = newDictionary[key1].depCountry
Try this to get all the list at first, then your desired element (say the First in your case):
var desiredElementCompoundValueList = new List<YourType>();
dic.Values.ToList().ForEach( elem =>
{
desiredElementCompoundValue.Add(elem.ComponentValue("Dep"));
});
var x = desiredElementCompoundValueList.FirstOrDefault();
To get directly the first element value without a lot of foreach iteration and variable assignment:
var desiredCompoundValue = dic.Values.ToList().Select( elem => elem.CompoundValue("Dep")).FirstOrDefault();
See the difference between the two approaches: in the first one you get the list through a ForEach, then your element. In the second you can get your value in a straight way.
Same result, different computation ;)
There are a bunch of such methods:
.First .FirstOrDefault .Single .SingleOrDefault
Choose which suits you best.
var firstObjectsOfValues = (from d in dic select d.Value[0].ComponentValue("Dep"));
I would to it like this:
//Dictionary object with Key as string and Value as List of Component type object
Dictionary<String, List<Component>> dic = new Dictionary<String, List<Component>>();
//from each element of the dictionary select first component if any
IEnumerable<Component> components = dic.Where(kvp => kvp.Value.Any()).Select(kvp => (kvp.Value.First() as Component).ComponentValue("Dep"));
but only if it is sure that list contains only objects of Component class or children

Generate a map of list element indices using Linq

I want to take a List, and generate a Dictionary which maps each element to its index in the List. I can do this like so, for a List<string>:
var myList = new List<string>{ /* populate list */ };
var orderMap = new Dictionary<string, int>();
foreach (var element in myList)
{
orderMap[element] = myList.IndexOf(element);
}
Basically, I want to take a list like:
Apple
Banana
Orange
And return a map showing indices:
Apple -> 0
Banana -> 1
Orange -> 2
How can I do this with Linq? I think something like this should work:
orderMap = myList.Select( x => /* return a key value pair mapping x to myList.IndexOf(x) */ );
But I can't figure out the right syntax for it. Besides, can you refer to the list itself in the delegate used for Select?
While you can refer to the list within the delegate, it's not generally a good idea. You really want to use the overload of Select which provides the index as well as the value:
var dictionary = list.Select((value, index) => new { value, index })
.ToDictionary(p => p.value, p => p.index);
Note that this will throw an exception if you have any duplicate elements.
You could try the ToDictionary extension method:
int index = 0;
orderMap = myList.ToDictionary(x => x, x => index++);
Take a look at this overload of ToDictionary<TKey, TValue>(). It takes to functions to convert the input element into a Key and a Value.
e.g.
var myList = new List<string>{ /* populate list */ };
var orderMap = myList.ToDictionary(x => myList.IndexOf(x), x => x);
However, one problem with this is if the elements of myList aren't unique.

Most elegant way to convert string array into a dictionary of strings

Is there a built-in function for converting a string array into a dictionary of strings or do you need to do a loop here?
Assuming you're using .NET 3.5, you can turn any sequence (i.e. IEnumerable<T>) into a dictionary:
var dictionary = sequence.ToDictionary(item => item.Key,
item => item.Value)
where Key and Value are the appropriate properties you want to act as the key and value. You can specify just one projection which is used for the key, if the item itself is the value you want.
So for example, if you wanted to map the upper case version of each string to the original, you could use:
var dictionary = strings.ToDictionary(x => x.ToUpper());
In your case, what do you want the keys and values to be?
If you actually just want a set (which you can check to see if it contains a particular string, for example), you can use:
var words = new HashSet<string>(listOfStrings);
You can use LINQ to do this, but the question that Andrew asks should be answered first (what are your keys and values):
using System.Linq;
string[] myArray = new[] { "A", "B", "C" };
myArray.ToDictionary(key => key, value => value);
The result is a dictionary like this:
A -> A
B -> B
C -> C
IMO, When we say an Array we are talking about a list of values that we can get a value with calling its index (value => array[index]), So a correct dictionary is a dictionary with a key of index.
And with thanks to #John Skeet, the proper way to achieve that is:
var dictionary = array
.Select((v, i) => new {Key = i, Value = v})
.ToDictionary(o => o.Key, o => o.Value);
Another way is to use an extension method like this:
public static Dictionary<int, T> ToDictionary<T>(this IEnumerable<T> array)
{
return array
.Select((v, i) => new {Key = i, Value = v})
.ToDictionary(o => o.Key, o => o.Value);
}
If you need a dictionary without values, you might need a HashSet:
var hashset = new HashSet<string>(stringsArray);
What do you mean?
A dictionary is a hash, where keys map to values.
What are your keys and what are your values?
foreach(var entry in myStringArray)
myDictionary.Add(????, entry);
I'll assume that the question has to do with arrays where the keys and values alternate. I ran into this problem when trying to convert redis protocol to a dictionary.
private Dictionary<T, T> ListToDictionary<T>(IEnumerable<T> a)
{
var keys = a.Where((s, i) => i % 2 == 0);
var values = a.Where((s, i) => i % 2 == 1);
return keys
.Zip(values, (k, v) => new KeyValuePair<T, T>(k, v))
.ToDictionary(kv => kv.Key, kv => kv.Value);
}
Dictionary<int, string> dictionaryTest = new Dictionary<int, string>();
for (int i = 0; i < testArray.Length; i++)
{
dictionaryTest.Add(i, testArray[i]);
}
foreach (KeyValuePair<int, string> item in dictionaryTest)
{
Console.WriteLine("Array Position {0} and Position Value {1}",item.Key,item.Value.ToString());
}
The Question is not very clear, but Yes you can convert a string to Dictionary provided the string is delimited with some characters to support Dictionary<Key,Value> pair
So if a string is like a=first;b=second;c=third;d=fourth you can split it first based on ; then on = to create a Dictionary<string,string> the below extension method does the same
public static Dictionary<string, string> ToDictionary(this string stringData, char propertyDelimiter = ';', char keyValueDelimiter = '=')
{
Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
Array.ForEach<string>(stringData.Split(propertyDelimiter), s =>
{
if(s != null && s.Length != 0)
keyValuePairs.Add(s.Split(keyValueDelimiter)[0], s.Split(keyValueDelimiter)[1]);
});
return keyValuePairs;
}
and can use it like
var myDictionary = "a=first;b=second;c=third;d=fourth".ToDictionary();
since the default parameter is ; & = for the extension method.
You can create a dictionary from an IEnumerable<T>, including an array, via:
var dictionary = myEnumerable.ToDictionary(element => element.Key,
element => element.Value)
where Key and Value are the key and value you want to store in each dictionary element. Available in .NET Framework 3.5+/.NET Core 1.0+/.NET 5.0+. Official documentation.
If you want the dictionary values to be the elements from the original enumerable:
var dictionary = myEnumerable.ToDictionary(element => element.Key)
If you only need high-performance set operations, you may be able to use:
var words = new HashSet<string>(listOfStrings);
In simple terms, the HashSet class can be thought of as a Dictionary<TKey,TValue> collection without values. Official documentation.
(Note that a 'sequence' in an entirely unrelated object.
Originally submitted an existing answer edit but it was rejected by the author so posting separately, including with links to the official Microsoft documentation.)

Categories