I am trying to sort my arraylist.
The array list consists of data in time format.
Array:
9:15 AM, 10:20 AM
How should I sort it?
The result i get from below code is :
10:20 AM
9:15 AM
Below is my code:
String timeText = readFileTime.ReadLine();
timeSplit = timeText.Split(new char[] { '^' });
Array.Sort(timeSplit);
foreach (var sortedArray in timeSplit)
{
sortedTimeListBox.Items.Add(sortedArray);
}
Yes, since you simply split a string, you're merely sorting an array of strings (meaning 1 comes before 9 and it doesn't care about the decimal point). To get the sorting you desire, you need to first convert it into a DateTime like this:
timeSplit = timeText
.Split(new char[] { '^' });
.Select(x => new { Time = DateTime.Parse(x), String = x })
.OrderBy(x => x.Time)
.Select(x => x.String)
.ToArray();
Here, what we've done is:
Split the string as you had done before
Create a new anonymous type that contains the original string and also that string converted into a DateTime.
Ordered it by the DateTime property
Select'ed back to the original string
Converted it into an array
timeSplit now contains the strings sorted as you wanted.
Array.Sort(timeSplit, delegate(string first, string second)
{
return DateTime.Compare(Convert.ToDateTime(first), Convert.ToDateTime(second));
});
Related
I want to compare values of two comboboxes. The variables are of type var and they come like this: 27-12-2018
I want to compare these two values and for this purpose I have converted the value in date format and in string format.
This is meteorologycal charts.
var formattedDates = string.Join("_", Path.GetFileName(file).Split('_', '.').Skip(1).Take(3));
var formattedDates2 = string.Join("_", Path.GetFileName(file).Split('_', '.').Skip(1).Take(3));
if (!comboBox2.Items.Contains(formattedName))
{
comboBox2.Items.Add(formattedName);
}
if (!comboBox3.Items.Contains(formattedDates))
{
comboBox3.Items.Add(formattedDates);
}
if (!comboBox4.Items.Contains(formattedDates2))
{
comboBox4.Items.Add(formattedDates2);
}
listBox1.Items.Add(Path.GetFileName(file));
}
}
else
{
MessageBox.Show("Директорията Meteo не е октирта в системен диск 'C:\'");
Application.ExitThread();
}
var result = Directory
.EnumerateFiles(#"C:\Meteo", "*.dat")
.SelectMany(file => File.ReadLines(file))
.Select(line => line.Split(new char[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries))
.Select(items => new {
id = items[0],
date = DateTime.ParseExact(items[1], "dd-MM-yyyy", CultureInfo.InvariantCulture).ToString(),
date2 = items[1],
hours = items[2],
temperature = items[3],
presure = items[4],
windSpeed = items[5],
windDirect = items[6],
rain = items[7],
rainIntensity = items[8],
sunRadiation = items[12],
/* etc. */
})
.ToList();
var dates = result
.Select(item => item.date)
.ToArray();
I have the same values in two formats - String and Date, but I dont know how to compare two comboboxes (if firstCombo > secondCombo){ messagebox.show("")}
Convert your string to a DateTime type.
DateTime DT1 = DateTime.ParseExact("18/08/2015 06:30:15.006542", "dd/MM/yyyy HH:mm:ss.ffffff", CultureInfo.InvariantCulture);
Rearrange the format string to match whatever date format you are using.
Then you can just do:
if(DT1 > DT2)
Also FYI, VAR isnt a type, it just sets the type of the variable to whatever type is on the right side of the equals.
To compare values of two comboboxes, you first need to convert both values into a type that can be compared. In your case, you seem to want to compare dates.
Ex: 07-06-2019 > 06-06-2019 = True.
I would recommend you to get the current values from both comboboxes (combobox.Text) and create a DateTime object with them.
Then, you'll be able to compare them like you want.
DateTime date0 = Convert.ToDateTime(combobox0.Text);//"07-06-2019"
DateTime date1 = Convert.ToDateTime(combobox1.Text);//"06-06-2019"
int value = DateTime.Compare(date0, date1);
if (value > 0)
{
//date0 > date1
}
else
{
if (value < 0)
{
//date0 < date1
}
else
{
//date0 == date1
}
}
Finally, to answer your question, the best practice to compare combobox values is depending on what value you're trying to compare... If you want to compare dates like in your example, it is better to convert the values to DateTime. The only comparison you can make with strings, correct me if I'm wrong, is to check if the strings are equal or have the same value.
Another good practice is to use the TryParse method associated to the type of value you want to convert/compare. Most of, if not all, basic types in c# have this method associated to them.
https://learn.microsoft.com/en-us/dotnet/api/system.datetime.tryparse?view=netframework-4.8
DateTime date0;
//Take text from combobox0, convert it and put the result in date0
bool success = DateTime.TryParse(combobox0.Text, out date0);
if(success)
{
//Your date has been converted properly
//Do stuff
}
I've defined List
private class Kamery
{
public int iIndeks;
public string strNazwa;
public Kamery(int Indeks, string Nazwa)
{
iIndeks = Indeks;
strNazwa = Nazwa;
}
}
List<Kamery> lKamery = new List<Kamery>();
I'd like to cast searched list of names to string array like:
string[] strNazwa = (string)lKamery.Find(item => item.iIndeks == iIndeks).strNazwa.ToArray();
But compiler says Cannot convert type 'char[]' to 'string'
Why? How it needs to be done?
I think you want:
string[] strNazwa = lKamery.Where(item => item.iIndeks == iIndeks)
.Select(item => item.strNazwa)
.ToArray();
That will give you a string array that contains each of the strNazwa values from the list for items that meet the Where condition.
Here's what your original code was doing:
string[] strNazwa = (string)
// get the one item that matches the condition
lKamery.Find(item => item.iIndeks ==Indeks)
// get the strNazwa property from that one item
.strNazwa
// return the string as a char array
.ToArray();
When you try to cast the char[] to a string it fails since you can't cast it. You can create a string from a character array but not via a cast.
I think your problem is that .Find returns only 1 value , the first match in the list.
https://msdn.microsoft.com/en-us/library/x0b5b5bc(v=vs.110).aspx
This value will be a string and by using .toArray , you are converting that string to a char[ ] and then trying to cast it back to string.
I'm not that good at c# , so the generic solution would be:
Declare the array, do a foreach and every time the id matches put the name into the array and inc the index. This limits it somewhat as you have to have a fixed size, would probably be better to use List instead.
trying to select the max digit from a list of strings:
int maxDigit = this.myList.Where(x=> x.Name.Any(Char.IsDigit))
.Select(x => int.Parse(x.Name)).DefaultIfEmpty(0).Max();
It is int.Parse(x.Name) which is causing an exception as this is returning the entire name string e.g. 'myValue99' which of course cannot be parsed to an int. I just want to return 99. I don't know where the digits will be in the string therefore cannot for example take the last two.
I need the DefaultIfEmpty for cases where the string does not contain a number.
Assuming you want the max number and not the max digit, all you need is a function to convert "stuff99" to 99. Then the Linq part becomes child's play:
int maxNumber = myList.Max(ExtractNumberFromText);
or, to be closer to your specs:
int maxNumber = myList
.Select(ExtractNumberFromText)
.DefaultIfEmpty(0)
.Max();
#Codecaster already pointed to a few applicable answers on this site for the second part. I adopted a simple one. No error checking.
// the specs: Only ever going to be my stuff1, stuff99
int ExtractNumberFromText(string text)
{
Match m = Regex.Match(text, #"\d*");
return int.Parse(m.Groups[0].Value); // exception for "abc"
// int.Parse("0" + m.Groups[0].Value); // use this for default to 0
}
you should only select and parse the Digit characters out of your string
int maxDigit = this.myList.Where(x => x.Name.Any(Char.IsDigit))
.Select(x => int.Parse(new string(x.Name.Where(Char.IsDigit).ToArray())))
.DefaultIfEmpty(0).Max();
Assuming the input can contain the following categories:
nulls
Empty strings
Strings with only alphabetical characters
Strings with mixed alphabetical and numerical characters
Strings with only numerical characters
You want to introduce a method that extracts the number, if any, or returns a meaningful value if not:
private static int? ParseStringContainingNumber(string input)
{
if (String.IsNullOrEmpty(input))
{
return null;
}
var numbersInInput = new String(input.Where(Char.IsDigit).ToArray());
if (String.IsNullOrEmpty(numbersInInput))
{
return null;
}
int output;
if (!Int32.TryParse(numbersInInput, out output))
{
return null;
}
return output;
}
Note that not all characters for which Char.IsDigit returns true can be parsed by Int32.Parse(), hence the TryParse.
Then you can feed your list to this method:
var parsedInts = testData.Select(ParseStringContainingNumber)
.Where(i => i != null)
.ToList();
And do whatever you want with the parsedInts list, like calling IEnumerable<T>.Max() on it.
With the following test data:
var testData = new List<string>
{
"۱", // Eastern Arabic one, of which Char.IsDigit returns true.
"123",
"abc456",
null,
"789xyz",
"foo",
"9bar9"
};
This returns:
123
456
789
99
Especially note the latest case.
To find the max digit (not number) in each string:
static void Main(string[] args)
{
List<string> strList = new List<string>() { "Value99", "46Text" };
List<int> resultList = new List<int>();
foreach (var str in strList)
{
char[] resultString = Regex.Match(str, #"\d+").Value.ToCharArray();
int maxInt = resultString.Select(s => Int32.Parse(s.ToString())).Max();
resultList.Add(maxInt);
}
}
It can be simple using Regex.
You stated 99, so you need to span more than one digit:
var maxNumber = myTestList.SelectMany(x => getAllNumnbersFromString(x.Name)).DefaultIfEmpty(0).Max();
static List<int> getAllNumnbersFromString(string str)
{
List<int> results = new List<int>();
var matchesCollection = Regex.Matches(str, "[0-9]+");
foreach (var numberMatch in matchesCollection)
{
results.Add(Convert.ToInt32(numberMatch.ToString()));
}
return results;
}
One digit only check:
int maxNumber = myTestList.SelectMany(x => x.Name.ToCharArray().ToList())
.Select(x => Char.IsDigit(x) ? (int)Char.GetNumericValue(x) : 0)
.DefaultIfEmpty(0).Max();
Probably there's a slicker way to do this but I would just do:
int tmp = 0;
int maxDigit = this.myList.Where(x=> x.Name.Any(Char.IsDigit))
.Select(x =>
(int.TryParse(x.Name,out tmp ) ? int.Parse(x.Name) : 0 ) ).Max();
You have to remember that Parse will error out if it can't parse the value but TryParse will just give you false.
public static bool IsAnagramOf(this string word1, string word2)
{
return word1.OrderBy(x => x).SequenceEqual(word2.OrderBy(x => x));
}
I'm currently pulling everything from a large xml file with all english words. I'm then comparing each word against the given string to see if it's an anagram. I'm then storing each correct word and returning them.
However...
I'm wanting to make it so the anagrams do not have to be of equal string length.
For example: "Hello" contains "Hello", "Hell", "He" etc...
Is there anyway to do this that's relatively small in code?
Thanks!
Edit: So including subanagrams as well as anagrams of equal length.
Maybe your method should be called ContainsTheSameSetOfLetters?
public static bool ContainsTheSameSetOfLetters(this string word1, string word2)
{
var chars = new HashSet<char>(word1);
return word2.All(x => chars.Contains(x));
}
If you care about number of time particular letter is being used, you can use following:
public static bool ContainsTheSameSetOfLetters(string word1, string word2)
{
var chars = word1.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count());
return word2.GroupBy(x => x).All(g => chars.ContainsKey(g.Key) && chars[g.Key] >= g.Count());
}
Instead of using SequenceEqual, try creating an extension method that checks that the sequence starts with another sequence.
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.