Sorting array by length - c#

I'm wanting to sort this array by length but how will I do that? I searched the web for a while but couldn't find anything. The code is supposed to sort an array given at random by each strings length in the string array, but I can't get anyway of declaring how I want it to sort.
public class Kata
{
public static string[] SortByLength (string[] array)
{
Array.Sort(array);
return array;
}
}

Well, in order to sort the array in place you should provide rule of sorting:
Array.Sort(array, (x, y) => x.Length.CompareTo(y.Length));
The method can be
public static string[] SortByLength (string[] array) {
//TODO: validate array and its items here; they must be not null
Array.Sort(array, (x, y) => x.Length.CompareTo(y.Length));
return array;
}

Use linq...
public static string[] SortByLength (string[] array) =>
array.OrderBy( x => x?.Length ?? 0 ).ToArray();

Dude, this is how it should work.
Array.Sort(array, StringComparer.InvariantCulture);

Related

How do you sort array of arrays in c#?

I'm trying to sort a list of intervals based on start time (which is the first element).
public static int[][] SortIntervals(int[][] intervals)
{
intervals.Sort(Comparer<int[]>.Create((a, b) => a[0].CompareTo(b[0]))); // error
return intervals;
}
Error -CS1503 Argument 1: cannot convert from 'System.Collections.Generic.Comparer<int[]>' to 'System.Array'
I can sort a list of intervals just fine, maybe I'm missing the correct syntax for it.
public static List<int[]> SortIntervals(List<int[]> intervals)
{
intervals.Sort(Comparer<int[]>.Create((a, b) => a[0].CompareTo(b[0])));
return intervals;
}
You are right, in case of array you should use different syntax Array.Sort:
public static int[][] SortIntervals(int[][] intervals)
{
if (null == intervals)
throw new ArgumentNullException(nameof(intervals));
Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0]));
return intervals;
}

How can I get a sorted `List<string>` based on an associated numeric index

I want to sort a string using indexes, but it's not working after 10th index, 10th/later indexes added after 1st index in the list after using Sort() method.
I have tried below code, but it's not working.
List<string> stringList = new List<string>();
foreach (ManagementObject disk in objectSearcher.Get() )
{
stringList.Add(string.Format("{0, -15} {1,-35} {2, -20}",
disk.GetPropertyValue("Index"),
disk.GetPropertyValue("Model"),
diskSize));
}
stringList.Sort();
In the above scenario, the code is working fine for 0-9 indexes but for later indexes, this is not working as expected.
Put your object into a class structure and work with that strong type as long as possible:
public class DiskInfo
{
private int index = 0;
private string model = String.Empty;
private unsigned long size = 0;
public int getIndex() { return index; }
public string getModel() { return model; }
public unsigned long getSize() { return size; }
public DiskInfo(int index, string model, unsigned long size)
{
this.index = index;
this.model = model;
this.size = size;
}
public string ToString()
{
return string.Format("{0, -15} {1,-35} {2, -20}", index, model, size);
}
}
// ...
List<DiskInfo> lst = new List<DiskInfo>();
foreach (ManagementObject disk in objectSearcher.Get() )
{
lst.Add(new DiskInfo(
disk.GetPropertyValue("Index"),
disk.GetPropertyValue("Model"),
diskSize
));
}
Adjust types as needed.
Then you can use simple linq to sort.
lst = lst.OrderBy(x => x.getIndex());
On top of that you get IDE support and compiler errors instead of trying to figure out why you get format exceptions, etc when mucking around with strings.
If your input data is not of the correct data type, then cast it then and there.
For example, index gets passed as a string:
string strIdx = "15";
lst.Add(new DiskInfo(int.Parse(strIdx)), ...)
It's not working after 10th index.
That is because List().Sort invoke string's comparison function.In string comparison "0" is less than "1", "1" is less than "11" and "12" is less than "2" etc.So it is not working after 10.
You can definition a sample comparison function as below:
public static int Compare(string a, string b)
{
return int.Parse(a.Substring(0, 15)).CompareTo(int.Parse(b.Substring(0, 15)));
}
and then invoke it in sort method:
stringList.Sort(Compare);
The prerequisite is that your format is satisfied that its first 15 characters can convert to an integer.
You are probably looking for the "logical sort order" seen in Windows Explorer. Below I have replaced the default string comparer with a comparer using that API: StrCmpLogicalW
class Program
{
public sealed class NaturalStringComparer : IComparer<string>
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
public int Compare(string a, string b) => StrCmpLogicalW(a, b);
}
static void Main()
{
var stringList = new List<string>();
var index = 0;
while (index < 12)
{
stringList.Add($"{index,-15} {"Model",-35} {"35GB",-20}");
index++;
}
stringList.Sort(new NaturalStringComparer());
foreach (var s in stringList)
{
Console.WriteLine(s);
}
}
}
You seem to be deliberately left aligning index your numbers, which will mean that the ascending string sorted sequence of 1 through 12 would would be 1, 11, 12, 2, 3, 4, ...
Since you have the index value during the creation of the string, it would be wasteful to again parse the number out of the string in order to sort it. It would be better to retain the index and the string separately in a suitable data structure, sort by the index, and then project out just the string.
Updated for OP's new Question
Creating a custom POCO class (with or without an IComparable implementation) seems overkill everytime you need to sort an enumerable of related data by one of its properties.
Instead, you can easily build up a sortable anon class, struct or tuple containing the sortable integer and the concatenated string, then sort, then project out just the string. Either way, OP's GetPropertyValue method appears to return (reflect) a weak type such as object or string - accepted answer wouldn't compile as it needs to cast index to an int.
Here's value tuple solution:
var tuples = new List<(int index, string str)>();
foreach (ManagementObject disk in objectSearcher.Get() )
{
var indexValue = int.Parse(disk.GetPropertyValue("Index"));
tuples.Add((indexValue, string.Format("{0, -15} {1,-35} {2, -20}",
indexValue,
disk.GetPropertyValue("Model"),
diskSize)));
}
// Sort by index, and project out the assembled string.
var myList = tuples
.OrderBy(t => t.index)
.Select(t => t.str)
.ToList();
Original Answer, OP had a simple loop
What I've done below is to keep a Value tuple of the original string, and the parsed integer value of the first 15 digits.
Note that this will break if there are non-numeric characters in the first 15 characters of your string.
// Test Data
var strings = Enumerable.Range(0, 12)
.Select(i => (string.Format("{0, -15} {1,-35} {2, -20}", i, "Model", "35GB")));
// Project out a tuple of (index, string)
var indexedTuples = strings.Select(s => (idx: int.Parse(s.Substring(0, 15)), str: s));
var sorted = indexedTuples.OrderBy(t => t.idx)
.Select(t => t.str);

Alphanumeric string sorting with prifix and suffix

I have a alphanumeric string of array which contains some characters at end of string also. The problem is i'm able to sort only till before the last character.
Here is the my array
string[] ar = new string[] { "DV00154A", "DV00144A", "DV00111B", "DV00100A", "DV00199B", "DV00001A" };
i have tried some method but the sorted array skipping the sorting of last character. here is one of the approach which i have tried.
public static string ArraySort(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10,'0'));
}
public static void Main(string[] args)
{
string[] ar = new string[] { "DV00154A", "DV00144A", "DV00111B", "DV00100A",
"DV00199B", "DV00001A" };
var result = ar.OrderBy(x => ArraySort(x));
Console.WriteLine(string.Join(",",result.ToArray()));
}
which returning the below output
DV00001A,DV00100A,DV00111B,DV00144A,DV00154A,DV00199B
but the output i need should be like this
DV00001A,DV00100A,DV00144A,DV00154A,DV00111B,DV00199B
What about this solution:
public static string ArraySort(string input)
{
return $"{input.Substring(0, 2)}{input.Substring(7, 1)}{input.Substring(2, 5)}";
}
public static void Main(string[] args)
{
string[] ar = new string[] { "DV00154A", "DV00144A", "DV00111B", "DV00100A", "DV00199B", "DV00001A" };
Array.Sort(ar, (a, b) => StringComparer.OrdinalIgnoreCase.Compare(ArraySort(a), ArraySort(b)));
Console.WriteLine(string.Join(",", ar));
Console.ReadKey();
}
The ArraySort method rearranges the values in a sortable format: DV00154A -> DVA00154. That values are used the by the Array.Sort comparer method.
The only disadvantage that the ar array is sorted in-place...
Edit:
I found an even better solution: just take my ArraySort method with your Main method. Should work just fine. :) And it will not affect your ar array.
Edit 2:
Just fixed a little bug in my ArraySort method. (Sorry.)
Edit 3:
If you can ignore the DV-prefix, you could change the ArraySort method to this:
public static string ArraySort(string input)
{
return $"{input.Substring(7, 1)}{input.Substring(2, 5)}";
}
The logic is less complex and the resulting values are shorter. It should have a (marginal) better performance.

C#: How to check if all the elements in an array of boolean variables are of the same value (All true or All false)?

I have an array of boolean variables and I want to return true if all the elements in this array are of the same value, false otherwise. I know I can loop through all the elements, but I'm wondering if there are any faster ways in C#.
var allAreTheSame = myArray.All(a => a) || myArray.All(a => !a)
var result = array.Distinct().Count() == 1;
// Assuming the array is NOT empty
// Get first value
var firstValue = myArray.First();
// Check if all other values are identical
var allidentical = myArray.Skip(1).All(z => z == firstValue);
Enumerable.Range(0, array.Length-1).All(i => array[i] == array[i+1])
Edit: Fix after comments
Enumerable.Range(1, array.Length).All(i => array[i] == array[0])
var allAreTheSame = myArray.Distinct().Count() == 1
Just an alternative to David's approach, slightly shorter and possibly more efficient since I think the enumerator combination will cause the Array to be looped only once.
I would go for an extension method. I'd always love those methods:
The class containing the extension method will be:
public static class ExtensionMethods
{
public static bool AreAll<T>(this T[] source, Func<T, bool> condition)
{ return source.Where(condition).Count() == source.Count(); }
public static bool AreAllTheSame<T>(this IEnumerable<T> source)
{ return source.Distinct().Count() == 1; }
}
You see that I have 2 extension methods, one taking a Func and one taking no parameter.
The first one is called when you want to check if all the elements in the array has the same value (for example, all elements are true, or all elements are false).
The second one is called, when you don't want to check against a specific parameter, but if you just want to see if all the values are the same.
And than a little demo to demonstrate the extension method itself:
class Program
{
static void Main(string[] args)
{
bool[] array = { true, false, true, false, true };
bool[] trueArray = { true, true, true, true };
Console.WriteLine("Searching with a predicate:");
Console.WriteLine(array.AreAll(x => x).ToString());
Console.WriteLine(array.AreAll(x => !x).ToString());
Console.WriteLine(trueArray.AreAll(x => x).ToString());
Console.WriteLine(trueArray.AreAll(x => !x).ToString());
Console.WriteLine("Searching without a predicate:");
Console.WriteLine(array.AreAllTheSame().ToString());
Console.WriteLine(array.AreAllTheSame().ToString());
Console.WriteLine(trueArray.AreAllTheSame().ToString());
Console.WriteLine(trueArray.AreAllTheSame().ToString());
Console.ReadLine();
}
}
This will produce the following output:
Let's hope it helps.
Just for fun a little different solution:
!(array.Any(b => b) && array.Any(b => !b));
There are two loops here. One of them should exit on the first element in the array. The other one should exit on the first occurrence that is different from the first in the array. It will also return true for empty arrays.

Consuming an Array returned from a Method

from my function below, I am returning an array. In C# how would I consume that array?
public Array arrayFucntion()
{
// do something
foreach (var Objs in items)
{
list.Add(Objs.value1);
}
string[] myArray = list.ToArray();
MessageBox.Show(myArray.ToString());
return myArray;
}
Now how would I use it in a function like below
void consumeFunction()
{
var x = arrayFucntion();
// what do do to see values of the array
}
Return a string[], then you can do the for loop through the string array.
public string[]arrayFucntion()
void consumeFunction()
{
var x = arrayFucntion();
for (int i=0; i<x.Lenght; i++)
{
x[i]...
}
}
Make the return type string[] instead of Array.
You can iterate through the members:
foreach (string sArrayMember in x)
{
// Do something with s
}
You can also access any of the properties or members listed in the MSDN documentation, including Copy, Find, and Sort.
x is now an array object...
you can do foreach on it, or use linq.....or using direct addressing x[0]

Categories

Resources