Sort Descending directly - c#

I have
List<string> strs;
double[] values;
where the values array contains the value of each of the string in strs list
Say strs={"abc","def","ghi"}
and values={3,1,2}
this means "abc" has value 3 and so on.
I wish to sort strs and values ordered by values, such that it becomes
strs={"def","ghi","abc"}
values={3,2,1}
I am using
string[] strsArr = strs.ToArray();
Array.Sort(values, strsArr);//1. sort it ascendingly
strs = strsArr.ToList();
Array.Reverse(strs);//2. reverse it
Is there a way I can sort it in descending sequence directly without 2 phases?

You can use a Dictionary and Linq to solve this.
var dict = new Dictionary<string, double>()
{
{"abc",3},
{"def",1},
{"ghi",2}
};
var sorted = dict.OrderByDescending(g => g.Value)
.Select(g => g.Key)
.ToArray();
Note, unless you have a ToArray() at the end the sorting will be deferred till later enumerated and may accidentally be enumerated multiple times.

How about this:
var strs = new [] { "abc", "def", "ghi", };
var values = new [] { 3, 1, 2, };
strs =
strs
.Zip(values, (s, v) => new { s, v })
.OrderByDescending(sv => sv.v)
.Select(sv => sv.s)
.ToArray();

try use dictionary:
Dictionary<string, double> dictionary = new Dictionary<string, double>();
dictionary.Add("abc", 3);
dictionary.Add("def", 1);
dictionary.Add("ghi", 2);
var sortedDict = dictionary.OrderByDescending(x => x.Value);
double[] values = sortedDict.Select(x => x.Value).ToArray();
List<string> strs = sortedDict.Select(x => x.Key).ToList();

Related

C# Linq 2 Dimensional List Filter

Edit - Figuered this out thanks to #Monofuse:
List<List<int>> list1,
list2,
list2_flattened = list2.SelectMany(x => x).ToList(); // 1d list
list1 = list1.Select(x => x.Where(y => !list2_flattened.Contains(y)).ToList()).ToList(); // 2d list (definitely not the most efficient function, but my list is constrained to a size of about 20)
Given the 2 lists:
List<List<int>> list1;
List<List<int>> list2;
How would you filter the items in List1, such that you end up with items that don't exist in list2?
forgot to mention: list1 must keep the original structure (that is List<List>, so SelectMany isn't an option)
I'm looking for a linq solution
Thanks!
If I've understood you right, and you want to exclude list2 int values from list1 you can put
var result = list1
.Select(list => list
.Where(item => !list2
.SelectMany(dropList => dropList)
.Any(drop => drop == item))
.ToList())
.ToList();
For instance
List<List<int>> list1 = new List<List<int>>() {
new List<int>() { 1, 2, 2, 3, 3, 4, 4},
new List<int>() { 2,},
new List<int>() { 5, 6,}
};
// We should remove 2, 5, 3 whenever they appear in list1
List<List<int>> list2 = new List<List<int>>() {
new List<int>() { 2, 5},
new List<int>() { 3, 3},
};
var result = list1
.Select(list => list
.Where(item => !list2
.SelectMany(dropList => dropList)
.Any(drop => drop == item))
.ToList())
.ToList();
string report = string.Join(Environment.NewLine, result
.Select(line => $"[{string.Join(", ", line)}]"));
Console.Write(report);
Outcome:
[1, 4, 4]
[]
[6]
Not sure if you wanted to remove list1 lists where there is no longer anything in it. Also wasn't sure if you wanted to check that every item in a sublist matches all of a sublist of list2.
var list1 = new List<List<int>>();
var list2 = new List<List<int>>();
var flatList2 = list2.SelectMany(l2 => l2).Distinct();
var result = list1
.Select(o => o
.Where(inner => !flatList2.Contains(inner)))
.Where(o => o.Any());
The below one is exactly the same, it just has different variable names. I think it might help people understand a little more. As we are dealing with a two dimensional array, I always find it a little easier to think of it like a table.
var table = new List<List<int>>();
var table2 = new List<List<int>>();
var distinctColumns = table2.SelectMany(row => row).Distinct();
var result = table
.Select(row => row
.Where(column => !distinctColumns.Contains(column)))
.Where(row => row.Any());

Convert List of Dictionary<string, List> into list C# Linq

This is my source type => IEnumerable<IDictionary<string, IEnumerable<string>>>
This is my target type => IEnumerable<string>
Expected Output
List of strings
[
"ca:aws_client:firstElementIntheList]",
"ca:aws_client:secondElementInTheList]"
]
Actual Output
List of strings
[
"ca:aws_client:System.Linq.Enumerable+SelectListIterator`2[System.String,System.String]",
"ca:aws_client:System.Linq.Enumerable+SelectListIterator`2[System.String,System.String]"
]
Code
input
.ToList()
.SelectMany(d => d)
.Select(i => $"ca:{i.Key}:{i.Value.Select(l => l)}")
.ToList()
You're looking to use a result selector in SelectMany instead of a second select statement.
Something like this may be what you want:
var dict = new Dictionary<string, IEnumerable<string>>
{
{"one", new List<string> {"1","2","3"}},
{"two", new List<string> {"1","2","3"}}
};
var res = dict.SelectMany(d => d.Value, (a, b) => $"ca:{a.Key}:{b}");
foreach(var val in res)
Console.WriteLine(val);
/* output:
ca:one:1
ca:one:2
ca:one:3
ca:two:1
ca:two:2
ca:two:3
*/
Edit:
I've noticed you're actually using a List of Dictionaries. The solution is largely the same, but with more SelectMany.
var list = new List<Dictionary<string, IEnumerable<string>>>
{
new Dictionary<string, IEnumerable<string>> {
{"one", new List<string> {"1","2","3"}},
{"two", new List<string> {"1","2","3"}}
},
new Dictionary<string, IEnumerable<string>> {
{"three", new List<string> {"1","2","3"}},
{"four", new List<string> {"1","2","3"}}
}
};
var res = list.SelectMany(x => x)
.SelectMany(d => d.Value, (a, b) => $"ca:{a.Key}:{b}");
foreach(var val in res)
Console.WriteLine(val);
If someone can suggest a clean way to handle the multiple method syntax SelectMany other than stacking them, I'd like to know for my own edification.

C# Linq Find all indexes of item in List<int> within another List<int>

I have a List looks like:
List<int> List1= new List<int>(){3,4,5};
and another looks like:
List<int> List2 = new List<int>(){1,2,3,4,5,6};
How can I use Linq to get an array of all of the indices of List1 from List2 like below:
var ResultList = {2,3,4};
var ResultList = List1.Select(x => List2.IndexOf(x));
This is a longer solution but prevents a nested loop through the array which may be faster if the arrays are huge (but slower if the arrays are small).
List<int> List1= new List<int>(){3,4,5};
List<int> List2 = new List<int>(){1,2,3,4,5,6};
var lookup = new Dictionary<int, int>();
for(var i=0; i<List2.Count; i++) {
lookup[List2[i]] = i;
}
List<int> Result = List1.Select(i => {
int index;
return lookup.TryGetValue(i, out index) ? index : -1;
}).ToList();
You can also do the overloaded version of Select statement to select the Value and return the Index:
var result = List2.Select((a, b) => new {Value = a, Index = b})
.Where(x => List1.Any(d => d == x.Value))
.Select(c => c.Index).ToArray();
If your List2 contains more than one instance of a List1 value (or Equality) type, then you can use the indexed overload of Select to find all the duplicates:
var List1= new List<int>(){3,4,5};
var List2 = new List<int>(){1,2,3,4,5,6,1,2,3,5};
var result = List2.Select((x, idx) => Tuple.Create(x, idx))
.Where(t => List1.Contains(t.Item1))
.Select(x => x.Item2)
// 2,3,4,8,9
or better, using C#7 Value Tuples
List2.Select((x, idx) => (X:x, Idx:idx))
.Where(t => List1.Contains(t.X))
.Select(x => x.Idx);
(.IndexOf returns just the first index found in the target)

How to sort List according to value in an array

I have
List<string> strs;
double[] values;
where the values array contains the value of each of the string in strs list
Say strs={"abc","def","ghi"}
and values={3,1,2}
this means "abc" has value 3 and so on.
I wish to sort strs and values ordered by values, such that it becomes
strs={"def","ghi","abc"}
values={1,2,3}
Is there any easy way to achieve this?
The Array.Sort method has an overload that takes two arrays and sorts both arrays according to the values in the first array, so make an array out of the list:
string[] strsArr = strs.ToArray();
Then sorting them can't be simpler:
Array.Sort(values, strsArr);
And then back to a list, if you need that:
strs = strsArr.ToList();
You can use Enumerable.Zip, then sort the result, then extract the list of strings.
Something like:
var result = strs.Zip(values, (first, second) => new Tuple<string, double>(first, second))
.OrderBy(x => x.Item2)
.Select(x => x.Item1)
.ToList();
How are you setting up these collections? Or are you given these two parameters?
You could create a StringAndOrder class and use LINQ:
public class StringAndOrder
{
public string String { get; set; }
public double Order { get; set; }
}
List<StringAndOrder> list; //create with this structure instead
var orderedStrings = list.OrderBy(item => item.Order).Select(item => item.String);
var sortedStrs = strs.Select((i, s) => new {Value = values[i], Str = s})
.OrderBy(x => x.Value)
.Select(x => x.Str).ToList();
If you could logically put those values as properties of a class, such as:
class NameAndOrder
{
public string Name;
public int Order;
}
Then it would be better and more organized, and then you could do:
var items = new List<NameAndOrder>(strs.Count);
for (var i = 0; i < strs.Count; i++)
{
items.Add(new NameAndOrder { Name = strs[i], Order = values[i] });
}
items.Sort((a, b) => a.Order.CompareTo(b.Order));
Why Don't you use Dictionary Object..
Dictionary<string, int> dictionary =
new Dictionary<string, int>();
dictionary.Add("cat", 2);
dictionary.Add("dog", 1);
dictionary.Add("llama", 0);
dictionary.Add("iguana", -1);
// Acquire keys and sort them.
var list = dictionary.Keys.ToList();
list.Sort();
var strs = new[] { "abc", "def", "ghi" };
var values = new[] { 3, 1, 2 };
var newArr = strs.Select((s, i) => new { s, i })
.OrderBy(x => values[x.i])
.Select(x => x.s)
.ToArray();

create a dictionary using 2 lists using LINQ

I am trying to create a dictionary from 2 lists where one list contains keys and one list contains values. I can do it using for loop but I am trying to find if there is a way of doing it using LINQ.
Sample code will be helpfull. Thanks!!!!
In .NET4 you could use the built-in Zip method to merge the two sequences, followed by a ToDictionary call:
var keys = new List<int> { 1, 2, 3 };
var values = new List<string> { "one", "two", "three" };
var dictionary = keys.Zip(values, (k, v) => new { Key = k, Value = v })
.ToDictionary(x => x.Key, x => x.Value);
List<string> keys = new List<string>();
List<string> values = new List<string>();
Dictionary<string, string> dict = keys.ToDictionary(x => x, x => values[keys.IndexOf(x)]);
This of course assumes that the length of each list is the same and that the keys are unique.
UPDATE: This answer is far more efficient and should be used for lists of non-trivial size.
You can include the index in a Select expression to make this efficient:
var a = new List<string>() { "A", "B", "C" };
var b = new List<string>() { "1", "2", "3" };
var c = a.Select((x, i) => new {key = x, value = b[i]}).ToDictionary(e => e.key, e => e.value );
foreach (var d in c)
Console.WriteLine(d.Key + " = " + d.Value);
Console.ReadKey();
var dic = keys.Zip(values, (k, v) => new { k, v })
.ToDictionary(x => x.k, x => x.v);
You can use this code and working perfectly.
C# Code:
var keys = new List<string> { "Kalu", "Kishan", "Gourav" };
var values = new List<string> { "Singh", "Paneri", "Jain" };
Dictionary<string, string> dictionary = new Dictionary<string, string>();
for (int i = 0; i < keys.Count; i++)
{
dictionary.Add(keys[i].ToString(), values[i].ToString());
}
foreach (var data in dictionary)
{
Console.WriteLine("{0} {1}", data.Key, data.Value);
}
Console.ReadLine();
Output Screen:

Categories