Sorted ObservableCollection with KeyValuePair and duplicated keys - c#

I have a foreach loop. Each loop I get a value (long) and name (string) of an item.
Now I want to create an ObservableCollection<KeyValuePair<Int32, String>>() but not with the value, but with a new index starting with 0. The collection should be sorted by the value. If there is a duplicate value, both items should be added.
Example:
var tempList= new SortedList<long, String>();
foreach (INetworkItem item in ListOfItems)
{
long value = item.ticks;
string name = item.name;
// tried:
// tempList.Add(value , name );
...
}
Content ListOfItems:
3444423423, "aaaaaa"
9999457567, "bbbbbb"
1111100065, "cccccc"
3444423423, "aaaaaa"
After the foreach-loop I need an ObservableCollection<KeyValuePair<Int32, String>>() which looks like:
0, "cccccc"
1, "aaaaaa"
2, "aaaaaa"
3, "bbbbbb"
How can I do that?

First you need to sort the ListOfItems by ticks.
var items = ListOfItems.OrderBy(x => x.ticks);
Then you should convert them to the format you want
0, "cccccc"
1, "aaaaaa"
2, "aaaaaa"
3, "bbbbbb"
You can do this by Select
items = items.Select((x, i) => new KeyValuePair<int,string>(i, x.name));
Then initialize your collection with it.
var collection = new ObservableCollection<KeyValuePair<Int32, String>>(items);

Related

How to get first element from Value List of a Dictionary?

I have the following declaration and I need to get the first element from the list using key. Then after assigning that value to some variable again I need to remove that value alone from that list.
Dictionary<string, List<string>> data = new Dictionary<string, List<string>>();
For Example:
List<string> teamMembers = new List<string>();
teamMembers.Add("Country1Player1");
teamMembers.Add("Country1Player2");
teamMembers.Add("Country1Player3");
data.Add("Country1",teamMembers);
teamMembers = new List<string>();
teamMembers.Add("Country2Player1");
teamMembers.Add("Country2Player2");
teamMembers.Add("Country2Player3");
data.Add("Country2",teamMembers);
From the above dictionary, I need to select the Country1 's first element Country1Player1 and assign to some variable. After that I need to remove that value alone from the value list.
Expected output:
If I pass key as 'Country1' then it should give me Country1Player1 and that value needs to be removed the data dictionary. Key Country1 should contain only Country1Player2 & Country1Player3 in the list of values.
string firstTeamMember = null;
if (data.TryGetValue("Country1", out List<string> list) && list?.Any() == true)
{
firstTeamMember = list[0];
list.RemoveAt(0);
}
You could try sth like this:
if(data.TryGetValue("Country1", out var values))
{
var firstValue = values?.FirstOrDefault();
data["Country1"] = data["Country1"]?.Skip(1).ToList();
}

How can we Sort a dictionary<List<int>, List<int>> on the basis of two fields from value

As a part of key I am storing a List and in Value I want to store max and min values of that list. Later there will be many lists like that. I need to sort for the dictionary having minimum possible maximum element value and minimum possible minimum element value
Something like
var map= Dictionary<List<int>, List<int>>()
Consider few list like
List1=[21,65,98,9,2] List2=[3,46,78,09,17] List3=[3,6,0,98]
respective min and max for list1, list2 and list3 are [2,98], [3,78] and [0,98]. These values will be stored in the dictionary value(with associated list as key).
I want to sort in the dictionary, keeping a track of both min and max value.
Something like:
map= {[3,6,0,98] ,[0,98]} , {[21,65,98,9,2],[2,98]}, {[3,46,78,09,17], [3,78]}
From what I understand, you really just need to order the dictionary by the Value, which is really just the Min and Max elements from the Key. And the order should go by the Max elements and then by the Min elements if the Max elements are equal. So, given this data:
var dictionary = new Dictionary<List<int>, List<int>>
{
{ new List<int> {3,6,0,98 }, new List<int> {0,98 } },
{ new List<int> {21,65,98,9,2 },new List<int> {2,98 } },
{ new List<int> {3,46,78,09,17 }, new List<int> {3,78 } }
};
You can sort the dictionary using the OrderBy method, passing in a custom IComparer:
var sorted = dictionary.OrderBy(x => x.Value, new MinMaxCompararer());
MinMaxComparer here looks like:
class MinMaxCompararer : IComparer<List<int>>
{
public int Compare([AllowNull] List<int> x, [AllowNull] List<int> y)
{
int maxCompare = x[1].CompareTo(y[1]);
return maxCompare == 0
? x[0].CompareTo(y[0])
: maxCompare;
}
}
With this, iterating over the elements shows them sorted as you'd expect:
foreach (KeyValuePair<List<int>, List<int>> item in sorted)
{
Console.WriteLine($"Key: [{string.Join(",", item.Key)}]; Value: [{string.Join(",", item.Value)}]");
}
Key: [3,46,78,9,17]; Value: [3,78]
Key: [3,6,0,98]; Value: [0,98]
Key: [21,65,98,9,2]; Value: [2,98]

using TryGetValue from key and adding not working as intened

I have this code to retrieve a value(integer array) out of a dictionary Then increment one of the elements inside the integer array based on the if statement it is in..
Dictionary<string, int[]> ResultDic = new Dictionary<string, int[]>();
if (TeamOnePoint > TeamTwoPoint)
{
ResultDic.TryGetValue(TeamOneResult, out OutOfDic);
OutOfDic[0]++;
OutOfDic[1]++;
////ResultDic.Remove(TeamOneResult);
////ResultDic.Add(TeamOneResult, OutOfDic);
ResultDic[TeamOneResult] = OutOfDic;;
ResultDic.TryGetValue(TeamTwoResult, out OutOfDic);
OutOfDic[0]++;
OutOfDic[2]++;
////ResultDic.Remove(TeamTwoResult);
////ResultDic.Add(TeamTwoResult, OutOfDic);
ResultDic[TeamTwoResult] = OutOfDic;
}
Now the problem I have is that evertime I read the modified OutOfDic array back into the dictionary into the value part where I specified the Key, every value in the dictionary is modified as well, and not just the key I specified.
The commented part gives the same result as the non commented part. How do I fix this problem to only add the value to the specified key?
The behaviour you've described is only possible if you've added the same array to the dictionary multiple times. Since arrays are reference types every change will affect all values in the dictionay.
So instead of doing this(for example):
Dictionary<string, int[]> ResultDic = new Dictionary<string, int[]>();
int[] array = { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamOne", array);
ResultDic.Add("TeamTwo", array);
You should do this:
int[] array = { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamOne", array);
array = new int[] { 1, 2, 3, 4, 5 };
ResultDic.Add("TeamTwo", array);
Note that it's not necessary to re-assign the array to the dictionary for the same reason (it's a reference type). So you can remove these lines:
ResultDic[TeamOneResult] = OutOfDic;;
// ....
ResultDic[TeamTwoResult] = OutOfDic;

IEnumerable - exclude using an array

Does anyone know if it's possible to create a new IEnumerable by using an array parameter to exclude values.
For instance, below is an example of how I imagine it would look.
class Item
{
public int id { get; set; }
public string name { get; set; }
}
IEnumerable looks like this:
item1 {id = 1}
item2 {id = 2}
item3 {id = 3}
I want to create a new IEnumerable but exclude the id numbers in the array.
Made up code to suggest idea:
Int32[] arrayList = {1,2};
var newIEnumerable = _exisitingIEnumerable.Where(o => (o.id NOT IN arrayList));
Looking at your question again, when the element type of _exisitingIEnumerable is not the same as that of arrayList, you will need to use Where to filter out the elements of arrayList
_exisitingIEnumerable.Where(o => !arrayList.Contains(o.Id))
Original answer:
_exisitingIEnumerable.Except(arrayList)
will return the distinct elements from _exisitingIEnumerable that are not in arrayList
If you need duplicates, you can use
_exisitingIEnumerable.Where(o => !arrayList.Contains(o))
What's wrong with the approach you suggested in the question? You can use Where and check if the array contains the value. Below the example using List as a target collection:
var myList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
int[] myArray = { 1, 2, 3 };
var result = new List<int>(myList.Where(n => !myArray.Contains(n)));

Sorting an array related to another array

I have two arrays, x and y, where y is the value of the tens of every element in x. Now, I want to sort y. But, the order of y will be different of x's. So, I can't tell after sorting which element in y was related to, for instance, x[0].
I want a "double sorting" maybe.
Array.Sort has an overload that accepts two arrays; one for the keys, and one for the items. The items of both are sorted according to the keys array:
int[] keys = { 1, 4, 3, 2, 5 };
string[] items = { "abc", "def", "ghi", "jkl", "mno" };
Array.Sort(keys, items);
foreach (int key in keys) {
Console.WriteLine(key); // 1, 2, 3, 4, 5
}
foreach (string item in items) {
Console.WriteLine(item); // abc, jkl, ghi, def, mno
}
So in your case, it sounds like you want:
Array.Sort(y,x); // or Sort(x,y); - it isn't 100% clear
How about?
var selectedArr = new int[] { 1, 3, 5, 7, 9 };
var unorderArr = new int[] { 9, 7, 5, 3, 1 };
var orderedArr = unorderArr.OrderBy(o => selectedArr.IndexOf(o));
If we have two arrays of complex objects and want to sort them according to one of the two arrays then we can use the next approach:
// We want to sort "people" array by "Name" and
// accordingly to it reorder "countries" array.
Person[] people = new Person[]
{
new Person {Name = "Fill"},
new Person {Name = "Will"},
new Person {Name = "Bill"},
};
Country[] countries = new Country[]
{
new Country {Name = "Canada"},
new Country {Name = "UK"},
new Country {Name = "USA"}
};
// Here we sort "people" array, but together with each "Person"
// in sorted array we store its "index" in unsorted array. Then we
// will use this "index" to reorder items in "countries" array.
var sorted = people
.Select((person, index) => new {person, index})
.OrderBy(x => x.person.Name)
.ToArray();
// Here "people" array is sorted by "Name", and
// "contries" array is reordered accordingly to it.
people = sorted.Select(x => x.person).ToArray();
countries = sorted.Select(x => countries[x.index]).ToArray();
Another approach is to use overload of the method Array.Sort with IComparer. At first we should implement IComparer:
private class PeopleComparer : IComparer<Person>
{
public int Compare(Person x, Person y)
{
return x.Name.CompareTo(y.Name);
}
}
And then we can sort two our arrays:
Array.Sort(people, countries, new PeopleComparer());
Here is complete sample that demonstrates these two approaches.
If y is always the tens value of x, y probably shouldn't exist - you should probably just calculate it's value directly off of x when needed.
In general, sorting parallel arrays is only possible (without hand rolling a sort algorithm) when the sort algorithm takes a custom "swap" function, which you can implement in terms of swapping elements in both arrays simultaneously. std::sort in C++ and qsort in C don't allow this.
Also in the general case, consider a single array where the element is a pair of items, rather than a parallel array for each item. This makes using "standard" algorithms easier.

Categories