I would like to know how to write a Linq (using lambda Expression in standard dot notation) query.
I have an array of some names, and I would like to retrevie a new array of names based on one statement. This is: Order the array of names, and return a new list from the name which starts on some specific letter (lets say letter M) on.
This is my current array:
string[] arrNames = { "Mike", "Zach", "Ella", "Allan", "Jo", "Roger", "Tito" };
I would like to return names like this: Mike, Roger, Tito, Zach - these 4;
Other 3 names (Allan, Ella and Jo are names which start with a letter that are in the alphabetica order bellow letter "M".
This is not the same as using Operator "StartsWith". This one only selects the names started on the specific letter. I would like to get all the names which are in alphabetical order from this letter and on (so names started from M to Z).
So retun list with names starts with letter "M" or above looking on the alphabetical order.
Mitja
var result = arrNames.Where(i => String.Compare("M", i) <= 0)
.OrderBy(i => i);
Looks like you need this:
arrNames.Where(n => string.Compare(n, "M") >= 0)
which returns all the names alphabetically greater (or equal) "M", in the default order ({ Mike, Zach, Roger, Tito } in your case).
If you want to sort it additionally, use
arrNames.Where(n => string.Compare(n, "M") >= 0).OrderBy(n => n)
This gives { Mike, Roger, Tito, Zach }.
arrNames.Where(s => string.Compare(s,"M",StringComparison.InvariantCultureIgnoreCase) >= 0).OrderBy(s => s);
if you want case-insensitive comparisons. Or use StringComparison.InvariantCulture for case-sensitive. It is usually a good idea to specify the culture for string comparisons (e.g. you can use the current culture, or the invariant culture).
If your whole point of sorting is just to get at the items beyond "M", then you may omit the OrderBy.
Related
I am new in c#.So please help.
The first line of input has a unique integer N that indicates the number of sets of strings, each set may contain between 1 and 50 inclusive elements, and each of the strings of the set may contain between 1 and 50 inclusive characters.
How i take input from user above this condition??
example:
enter integer number:3
My dream is big
I want to go school
You are so sweet
Here's what you need to do.
Split the string into array.
Sort the array using an IComparer that compares the length of each string in the array
Join the string array into a single string
See this function below:
public static string SortStringByLength(string input, Order order) {
string[] words = input.Split(' ');
if (order == Order.ASC)
Array.Sort(words, (x, y) => x.Length.CompareTo(y.Length));
else
Array.Sort(words, (x, y) => y.Length.CompareTo(x.Length));
return string.Join(" ", words);
}
And here's a demo to see it in action.
This question already has answers here:
Alphanumeric sorting using LINQ
(12 answers)
Closed 6 years ago.
I have a list containing data with string and number. I have to order it in ascending and descending order.
id data
------------------
1 data1#%
2 data10
3 data
4 #$data
5 data2
I fetch the record and store it in list "List". Then I order it in ascending, but "data10" is coming in b/w "data1" and "data2". Below is my code
var o/p = List.OrderBy(x => x.data);
expected output - data1, data2 and data10
You are currently sorting it based on the string values, which will sort it by dictionary value. In a dictionary, "10" will appear between "1" and "2" because that is alphabetical order - it does not recognize that it is sorting numbers.
True alphanumeric sorting can get pretty complex, but based on your data you might be able to simplify it. Assuming your string "data1", "data2", and "data10" is a consistent pattern, you can do something like this:
var op = List.OrderBy(x => int.Parse(x.data.substring(4)));
Alternatively, if the value before the number isn't a constant length, you can use Regex to pull the number value out:
var op = List.OrderBy(x => int.Parse(Regex.Match(x.data, "\\d+").Value));
To get what you want, you need to pad the numeric portion in your order by clause, something like:
var o/p = List.OrderBy(x => PadNumbers(x.Data));
where PadNumbers could be defined as StackOverflow user Nathan has written here:
public static string PadNumbers(string input)
{
return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
}
This pads zeros for any number (or numbers) that appear in the input string so that OrderBy sees:
data0000000001
data0000000010
data0000000002
The padding only happens on the key used for comparison. The original strings (without padding) are preserved in the result.
Note : This approach assumes a maximum number of digits for numbers in the input.
I've recently been given a new project by work to convert Any given string into 1-3 letter abbreviations.
An example of something similar to what I must produce is below however the strings given could be anything:
switch (string.Name)
{
case "Emotional, Social & Personal": return "ESP";
case "Speech & Language": return "SL";
case "Physical Development": return "PD";
case "Understanding the World": return "UW";
case "English": return "E";
case "Expressive Art & Design": return "EAD";
case "Science": return "S";
case "Understanding The World And It's People"; return "UTW";
}
I figured that I could use string.Split & count the number of words in the array. Then add conditions for handling particular length strings as generally these sentences wont be longer than 4 words however problems I will encounter are.
If a string is longer than I expected it wouldn't be handled
Symbols must be excluded from the abbreviation
Any suggestions as to the logic I could apply would be very appreciated.
Thanks
Something like the following should work with the examples you have given.
string abbreviation = new string(
input.Split()
.Where(s => s.Length > 0 && char.IsLetter(s[0]) && char.IsUpper(s[0]))
.Take(3)
.Select(s => s[0])
.ToArray());
You may need to adjust the filter based on your expected input. Possibly adding a list of words to ignore.
It seems that if it doesn't matter, you could just go for the simplest thing. If the string is shorter than 4 words, take the first letter of each string.
If the string is longer than 4, eliminate all "ands", and "ors", then do the same.
To be better, you could have a lookup dictionary of words that you wouldn't care about - like "the" or "so".
You could also keep an 3D char array, in alphabetical order for quick lookup. That way, you wouldn't have any repeating abbreviations.
However, there are only a finite number of abbreviations. Therefore, it might be better to keep the 'useless' words stored in another string. That way, if the abbreviation your program does by default is already taken, you can use the useless words to make a new one.
If all of the above fail, you could start to linearly move through string to get a different 3 letter word abbreviation - sort of like codons on DNA.
Perfect place to use a dictionary
Dictionary<string, string> dict = new Dictionary<string, string>() {
{"Emotional, Social & Personal", "ESP"},
{"Speech & Language","SL"},
{"Physical Development", "PD"},
{"Understanding the World","UW"},
{"English","E"},
{"Expressive Art & Design","EAD"},
{"Science","S"},
{"Understanding The World And It's People","UTW"}
};
string results = dict["English"];
Following snippet may help you:
string input = "Emotional, Social & Personal"; // an example from the question
string plainText = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Regex.Replace(input, #"[^0-9A-Za-z ,]", "").ToLower()); // will produce a text without special charactors
string abbreviation = String.Join("",plainText.Split(" ".ToCharArray(),StringSplitOptions.RemoveEmptyEntries).Select(y =>y[0]).ToArray());// get first character from each word
I must doing something wrong... But I can't figure it out!
I have an array with string in it. I'm trying to fins if the Array contains some words like Sales for example.
drillDownUniqueNameArray[0] = "[Sales Territory].[Sales Territories].[Sales Territory Group].&[North America]";//Inside the string array there is this string in index 0
drillDownUniqueNameArray.Contains("S")//Output false!
Array.IndexOf(drillDownUniqueNameArray,"S")//Output -1! <--Fixed My answer
drillDownUniqueNameArray.Contains("[Sales Territory].[Sales Territories].[Sales Territory Group].&[North America]") //Output true!
I thouhgt Contains should find even part of the string..
How can I find if this array have "S" or "Sales" for example?
You are asking if the array contains a string that exactly matches "S".
What you want is to ask if any of the strings in the array contains the character "S", something like:
drillDownUniqueNameArray.Any(v => v.Contains("S"))
You're checking if the array contains an element that's exactly "S" but I think you are trying to check whether the array contains an alement that contains an "S".
You could achieve this by the following statement:
drillDownUniqueNameArray.Any( str => str.Contains ("S") )
You can try this.
drillDownUniqueNameArray[0].Contains("s");
You can use LINQ:
var allWithSales = drillDownUniqueNameArray
.Where(str => str.Contains("Sales"));
ignoring the case:
var allWithSalesIgnoreCase = drillDownUniqueNameArray
.Where(str => str.IndexOf("sales", StringComparison.OrdinalIgnoreCase) >= 0);
If you want to find all that contain a word "Sales"(String.Split() = white-space delimiter)):
var allWordsWithSales = drillDownUniqueNameArray
.Where(str => str.Split().Contains("Sales", StringComparer.OrdinalIgnoreCase));
Now you can enumerate the query with foreach or use ToArray() or ToList to create a collection:
foreach(string str in allWithSales)
Console.WriteLine(str);
You are finding it in the array, but you should find the word in the string.
Use following if you want to check:
drillDownUniqueNameArray.Any(x=>x.Contains("Sales"));
Use following if want to get the strings which contains "Sales"
drillDownUniqueNameArray.Where(x=>x.Contains("Sales"));
When you do it like this:
drillDownUniqueNameArray.Contains("S")
it's not gonna check the values, you must do it like this:
drillDownUniqueNameArray[0].Contains("S") or drillDownUniqueNameArray.First().Contains("S")
like this way it checks the values inside the array not the arrays itself
How to sort this?
I have List of string with values like this
11-03-2013
11-03-2013 -Count=2
11-03-2013 -count=1
11-04-2013 -Count=1
11-04-2013 -Count=2
11-04-2013
Output should be, The one without the count should be on the last and the top most should be 1 followed by 1 and dates should be ordered by ascending.
11-03-2013 -Count=2
11-03-2013 -count=1
11-03-2013
11-04-2013 -Count=2
11-04-2013 -Count=1
11-04-2013
I tried this code but this is sorting this by descending
var edates= edates.OrderBy(e => e.Replace("-count=1", string.Empty).Replace("-count=2", string.Empty)).ToList();
I know that a simple class with properties can do the trick but doing that so would need to change other methods which would require a lot of work.
Regards
it is because you compare strings not dates. Create two functions: first substrings date part and parses it and second substrings the count part and returns parsed count(or 0 if length < 11) and then yourList.OrderBy(s=> f1(s)).ThenByDescending(s=> f2(s))
Here is #Guru Stron's solution in code
private static void sortList()
{
var dates = getDates();
var sorted = dates.OrderBy(f1).ThenByDescending(f2);
}
private static DateTime f1(string parse)
{
return DateTime.Parse(parse.Substring(0, 10));
}
private static int f2(string parse)
{
int sort;
if (parse.Length > 10) int.TryParse(parse.Substring(18), out sort);
else sort = 0;
return sort;
}
You first need to order by the date, then by the rest of the string, descending;
edates =
edates.OrderBy(x =>
DateTime.ParseExact(x.Substring(0, 10), "MM-dd-yyyy",
CultureInfo.InvariantCulture))
.ThenByDescending(x => x.Substring(10))
.ToList();
You ought to use a real class to simplify things and have a proper representation. That said, you can use the LINQ query syntax and take advantage of the let clause to store the result of splitting the text on a space and the equal symbol. If the split result has more than one element we can assume the count exists. Next, we order by the date (after parsing it) and then by parsing the count (descending).
Try this approach out:
string[] inputs =
{
"11-03-2013",
"11-03-2013 -Count=2",
"11-03-2013 -Count=1",
"11-04-2013 -Count=1",
"11-04-2013 -Count=2",
"11-04-2013"
};
var query = from input in inputs
let split = input.Split(' ', '=')
let count = split.Length > 1 ? int.Parse(split[2]) : 0
orderby DateTime.Parse(split[0]), count descending
select input;
foreach (var item in query)
{
Console.WriteLine(item);
}
The following should order as desired across different years and counts >= 10.
This won't be the "fastest" method (and it will most certainly not work with L2S/EF LINQ providers), but it should sort the given format correctly and fail-fast on invalid values. I would likely write the code like this (or use an IComparer with an equivalent setup) - mainly because it "reads simple" to me.
DateTime OrderableItem (string e) {
var date = e.Substring(0, 10);
return DateTime.ParseExact(date, "MM-dd-yyyy", CultureInfo.InvariantCulture)
}
int OrderableCount (string e) {
var m = Regex.Match(e, #"-count=(\d+)$", RegexOptions.IgnoreCase);
return m.Success
? int.Parse(m.Groups[1].Value)
: 0;
}
var res = seq.OrderBy(OrderableDate)
.ThenBy(OrderableCount);
I much prefer to take data, instead of excluding data.