public static IEnumerable<string> OrderingReversal()
{
string[] digits = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var res = digits.Where(w => w[1] == 'i')
.OrderByDescending(w => Convert.ToInt32(w)).ToList<string>();
return res;
}
I would like the output to be: "nine", "eight", "six" and "five" I tried to achieve this by the code I provided above. However, I am receiving runtime error: System.FormatException: 'Input string was not in a correct format.'
Any Help would be appreciated. Thank you!
CodePudding user response:
A big part of the solution is found in other answers like this one but more is needed to sort the results.
Here's a class that will take a list of strings and return them sorted by the numeric values they represent:
public delegate long ConvertStringToNumberDelegate(string number);
public class NumbersAsTextSorter
{
private readonly ConvertStringToNumberDelegate _convertStringToNumberFunction;
public NumbersAsTextSorter(ConvertStringToNumberDelegate convertStringToNumberFunction)
{
_convertStringToNumberFunction = convertStringToNumberFunction;
}
public IEnumerable<string> ReverseSort(IEnumerable<string> input)
{
var textWithNumbers = input.Select(i => new {input = i, value = _convertStringToNumberFunction(i)});
return textWithNumbers.OrderByDescending(t => t.value).Select(s => s.input);
}
}
This will create a collection of text inputs matched with numeric values. It sorts the collection by the numeric value and then returns the text inputs in that sorted order.
As you can see, a critical detail is missing. How do you convert "one" to 1, "two" to 2, and so forth?
For that you need an implementation of the delegate - ConvertStringToNumberDelegate
. You can get that by using the class in the the answer I referenced above.
For convenience I've copied that static method (for which I am explicitly not taking credit!) into a static class:
public static class TestToNumbers
{
private static Dictionary<string, long> numberTable =
new Dictionary<string, long>
{{"zero",0},{"one",1},{"two",2},{"three",3},{"four",4},
{"five",5},{"six",6},{"seven",7},{"eight",8},{"nine",9},
{"ten",10},{"eleven",11},{"twelve",12},{"thirteen",13},
{"fourteen",14},{"fifteen",15},{"sixteen",16},
{"seventeen",17},{"eighteen",18},{"nineteen",19},{"twenty",20},
{"thirty",30},{"forty",40},{"fifty",50},{"sixty",60},
{"seventy",70},{"eighty",80},{"ninety",90},{"hundred",100},
{"thousand",1000},{"million",1000000},{"billion",1000000000},
{"trillion",1000000000000},{"quadrillion",1000000000000000},
{"quintillion",1000000000000000000}};
public static long ToLong(string numberString)
{
var numbers = Regex.Matches(numberString, @"\w ").Cast<Match>()
.Select(m => m.Value.ToLowerInvariant())
.Where(v => numberTable.ContainsKey(v))
.Select(v => numberTable[v]);
long acc = 0, total = 0L;
foreach (var n in numbers)
{
if (n >= 1000)
{
total = (acc * n);
acc = 0;
}
else if (n >= 100)
{
acc *= n;
}
else acc = n;
}
return (total acc) * (numberString.StartsWith("minus",
StringComparison.InvariantCultureIgnoreCase) ? -1 : 1);
}
}
Now you can create an instance of NumbersAsTextSorter
which uses that static method to convert text to numbers. I've done that in this unit test which passes:
[TestMethod]
public void TestSorting()
{
var sorter = new NumbersAsTextSorter(TestToNumbers.ToLong);
var output = sorter.ReverseSort(new string[] { "one", "three hundred", "zero" });
Assert.IsTrue(output.SequenceEqual(new string[] { "three hundred", "one", "zero" }));
}
For clarity, this is passing in "one", "three hundred", and "zero" and asserting that after it's sorted, the sequence is "three hundred", "one", "zero".
CodePudding user response:
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string[] digits = { "Zero", "one", "two", "Three", "four", "five", "Six", "seven", "eight", "nine" };
var asc = OrderNumberStringsByValue(digits);
var dec = OrderNumberStringsByValue(digits, true);
string[] myDigits = { "Eight", "nine", "Five", "six" };
var myAsc = OrderNumberStringsByValue(myDigits);
var myDec = OrderNumberStringsByValue(myDigits, true);
Console.WriteLine($"asc: {string.Join(", ", asc)}");
Console.WriteLine($"dec: {string.Join(", ", dec)}");
Console.WriteLine($"myAsc: {string.Join(", ", myAsc)}");
Console.WriteLine($"myDec: {string.Join(", ", myDec)}");
Console.ReadLine();
}
public static IEnumerable<string> OrderNumberStringsByValue(IEnumerable<string> numbers, bool decending = false)
{
return numbers.OrderBy(n => (decending ? -1 : 1) * (int)Enum.Parse(typeof(Numbers), n.ToLower()));
}
}
enum Numbers : int
{
zero = 0,
one = 1,
two = 2,
three = 3,
four = 4,
five = 5,
six = 6,
seven = 7,
eight = 8,
nine = 9
}
}