I tried to solve a problem few days ago and almost solved with the help of SO. Unfortunately stuck into a situation that am unable to sort out. Here's the scenario:
Input:
[7, "aaa", "a", "cccccccccc", 5]
Output:
["a", "aaa", 5, 7, "cccccccccc"]
So you can see depending upon the number of letters in the element, the array should be sorted. In case of number, that should be sorted as well. At one point, the below code worked:
//Dynamic list where we can have string and integers
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(5);
aLst.Add("cccccc");
int val;
//What I did here, converted all items into string
//Checks if the list contains string
var letters = aLst.Where(i => !int.TryParse(i.ToString(), out val)).OrderBy(i => i.Length).ToList();
//Checks if the list contains number
var numbers = aLst.Where(i => int.TryParse(i.ToString(), out val)).OrderBy(i => int.Parse(i.ToString())).ToList();
//Finally from the number result set, taking the numbers to get their indexes and set them into the list accordingly
foreach (var number in numbers)
{
//Checks number index
var index = int.Parse(number.ToString());
if (letters.Count() >= index)
{
letters.Insert(index, number); //Assign index to numbers
}
else
{
letters.Insert(number);
}
}
foreach(var value in letters)
{
Console.WriteLine(value);
}
The above code gets me the expected result. But when the input is something as follows, it returns different result set that I can't able to set accordingly:
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(10);
aLst.Add(5);
aLst.Add("cccccc");
aLst.Add("cccccccccccc");
The result I get:
["a", 2, "aa", "aaa", 5, "cccc", 7, "cccccc", "cccccccccccc", 10]
Expected output:
["a", 2, "aa", "aaa", "cccc", 5, "cccccc", 7, 10, "cccccccccccc"]
Anything that I am doing wrong here or missed something? Any idea would be appreciated.
Code snippet: Sort Array Elements
CodePudding user response:
The key here is to check the type of the object. If is a string, use the string's length for the order, otherwise assume it is an int
and use the value itself for the order.
This will throw an exception if there are something else in the object list, for example an instance of some random class.
var list = new List<object> { 7, "aaa", "a", "cccccccccc", 5 };
// this assumes the elements in the array above (which can be anything) are only strings or integer
var ordered = list.OrderBy(x => x is string str ? str.Length : (int)x).ToList();
// print array to see results
Console.WriteLine(string.Join(",", ordered));
CodePudding user response:
I hope i understood your sorting intension correctly. You could use a custom comparer to isolate the comparison logic which could check if it is a string or a number. For example,
public class Comparer : IComparer<object>
{
public int Compare(object a, object b)
{
var valA = GetValue(a);
var valB = GetValue(b);
return valA.CompareTo(valB);
}
private int GetValue(object ch)
{
if(Int32.TryParse(ch.ToString(),out var val))
return val;
else
return ch.ToString().Length;
}
}
You could now use the Custom comparer with Linq easily.
var output = list.OrderBy(x=>x, new Comparer())
Note that this assumes you are dealing with strings and numbers only. If you need to include other types, you could include the required logic within the Custom Comparer
CodePudding user response:
List<dynamic> aLst = new List<dynamic>();
aLst.Add(7);
aLst.Add("aaa");
aLst.Add("aa");
aLst.Add("cccc");
aLst.Add("a");
aLst.Add(2);
aLst.Add(5);
aLst.Add("cccccc");
for (int i = 0; i < aLst.Count; i )
{
if (aLst[i] is int val)
{
aLst.RemoveAt(i);
aLst.Insert(0, val);
}
}
//var ty = aLst.Select(x => x.ToString());
var ordered = aLst.OrderBy(x => x is string str ? str.Length : (int)x).ToList();
Console.WriteLine(string.Join(",", ordered)); //a,2,aa,aaa,cccc,5,cccccc,7