I have Visual Studio 2019. The project is a .Net Windows Form on C# on .Net Framework 4.8.
I have got two arrays.
The first one contains a random number of string values (since they come on a string[]), for example:
AB5XHBC1
NMAK72B8
WB5XHBC1
KCZUH528
NZ9YHF3D
PFKR6WNA
The second one will always have the same length of the first one, but their values are date-strings, and it could be some string.empty or repeated values in some cases:
06/10/2020
08/05/2018
01/12/2020
01/01/2009
01/12/2020
What I need to do is sort the first array based on the second one dates. I tried the Array.Sort method but it does not give me the expected result. I'm not really sure if I have used it wrong.
The "null" values must be the firsts, then the newer date (on the top) to the older date (on the bottom), so the resulting array of this example would have to be sort like this (from 0 to 5 position):
WB5XHBC1
KCZUH528
PFKR6WNA
NMAK72B8
AB5XHBC1
NZ9YHF3D
Thanks in advance.
You could implement a comparer for your dates (which should implement IComparer<string>) and then use Array.Sort(keys, values, comparer) like so:
using System;
using System.Collections.Generic;
namespace Demo
{
static class Program
{
public static void Main()
{
string[] data =
{
"AB5XHBC1",
"NMAK72B8",
"WB5XHBC1",
"KCZUH528",
"NZ9YHF3D",
"PFKR6WNA"
};
string[] dates =
{
"06/10/2020",
"08/05/2018",
"",
"01/12/2020",
"01/01/2009",
"01/12/2020"
};
Array.Sort(dates, data, new CompareDates());
Console.WriteLine(string.Join("\n", data));
}
}
public sealed class CompareDates: IComparer<string>
{
public int Compare(string x, string y)
{
var xd = DateTime.TryParse(x, out DateTime d1) ? d1 : DateTime.MaxValue;
var yd = DateTime.TryParse(y, out DateTime d2) ? d2 : DateTime.MaxValue;
return yd.CompareTo(xd);
}
}
}
However, this gives the output as:
WB5XHBC1
KCZUH528
PFKR6WNA
AB5XHBC1
NMAK72B8
NZ9YHF3D
I believe this is because your expected results have an error. The second-oldest date is "08/05/2018", which corresponds to the string "NMAK72B8". Therefore, according to your specification, "NMAK72B8" should be second from the end - but in your expected results, "AB5XHBC1" is second from the end.
Try it online (.Net Fiddle).
One thing to watch out for is the date parsing. The code above parses the dates in the current locale, which is assumed to be UK (for the dd/mm/yyyy date format). If you want to parse other date formats, you'll have to change the code accordingly.
You can store these in a List of Tuple<string, DateTime>. I've hardcoded the values in the example below - as other commenters have said, you need to properly parse the date strings into proper DateTime objects, etc. I leave that exercise to you.
var list = new List<(string RandomString, DateTime Date)>
{
("AB5XHBC1", DateTime.Parse("06/10/2020")),
("NMAK72B8", DateTime.Parse("08/05/2018")),
("WB5XHBC1", DateTime.MaxValue), // simulating null, see below
("KCZUH528", DateTime.Parse("01/12/2020")),
("NZ9YHF3D", DateTime.Parse("01/01/2009")),
("PFKR6WNA", DateTime.Parse("01/12/2020")),
};
var sorted = list.OrderByDescending(x => x.Date);
For the case of the null dates appearing first, you can check if the particular date string is null. If it is, assign DateTime.MaxValue as a value, otherwise parse it and use the actual value. The logic of this check could resemble the one below:
string.IsNullOrEmpty(whateverStringDate) ? DateTime.MaxValue : DateTime.Parse(whateverStringDate);
This should point you in the right direction, #Matthew Watson's answer would be a much more elegant and complete solution.
Related
I have a file with various characters and either words as well as numbers. These numbers can be integers like a 1 or 12 (as an example) or they have a comma and countless digits after the comma.
for example:
",{"n":"Box","p":[-4.0,4.0,0.0],"r":[270.0,0.0,0.0],"s":[1.0,1.000006,1.000006],"c":[0.448529363,0.4280135,0.412251264],"m":"wood_14"}"
The file is read with File.ReadAllText and then passed to NewtonsoftJson via JsonProperty accordingly
for example:
[JsonProperty("s")]
public double[] Scale
{
get;
set;
}
For example, with Scale, I want to limit the decimal places to a maximum of 5 digits.
Is this possible and if so, how?
I have been trying for days with different things, but nothing has worked yet.
My idea was to intervene in the string I build first before passing that to Json there. But unfortunately this does not work. I tried it with regular expression like Notepadd++ makes for example.
(edit)
I don't know if you want it to serialize or deserialize. So I made code for both cases. You have to leave one variant or another
public class a
{
private double[] val;
[JsonProperty("s")]
public double[] Scale
{
get { return val;
// or
val?.Select(v => Math.Round(v, 5)).ToArray(); }
set {
val=value;
//or
val = value?.Select(v => Math.Round(v, 5)).ToArray();
}
}
}
if you want it in many properties you can make it as a function
double.ToString() will do it.
const double d = 0.123456789;
string s = d.ToString("G5");
Console.WriteLine(s);
That outputs 0.12346, showing that it rounds the 5 to 6.
Documentation for Double.ToString shows much more detailed examples of how to format numbers.
The number format (i.e. decimal separator) is culture-specific. If you want to use the current culture, then the above will work. If you always want a comma as the decimal separator, you'll have to call the overload that accepts an IFormatProvider for the specific culture.
I have a large string containing multiple ID's in my reservation program for overview purpose.
string example = "ID01-20/05-Table1\n ID02-04/06-Table2\n ID03-21/05-Table1\n"
This is just an example, but the string could grow or shrink as reservations get deleted or added.
Currently, the overview is sorted based on ID's, but is it also possible using date or tables?
So it views as:
string example = "ID01-20/05-Table1\n ID03-21/05-Table1\n ID02-04/06-Table2\n"
Would be best if possible using Console.Display(); but I also wouldn't mind using something to generate a temporary string/list/array/whatever and displaying it that way.
I've seen it on static strings, but I'm not too sure how it would work as ID's get added and deleted.
You can split the initial string into chunks
.Split('\n')
the match the date part in each chunk with a help of regular expression:
// one or two digits followed by slash and then one or two digits
Regex.Match(item, "[0-9]{1,2}/[0-9]{1,2}").Value
parse it into date
DateTime.TryParseExact(
...
"d/M", // day / Month format
null,
DateTimeStyles.AssumeLocal,
out var date)
and then order by for it.
Code:
using System.Linq;
using System.Text.RegularExpressions;
...
string example = "ID01-20/05-Table1\n ID02-04/06-Table2\n ID03-21/05-Table1\n";
string result = string.Join("\n", example
.Split('\n')
.OrderBy(item => DateTime.TryParseExact(
Regex.Match(item, "[0-9]{1,2}/[0-9]{1,2}").Value,
"d/M",
null,
DateTimeStyles.AssumeLocal,
out var date)
? date
: DateTime.MaxValue));
I'm beginner in c# and have this value of string:
123456
but want convert that string to my country money, want convert that string value to this:
123,456
always split three numbers with comma for example, if string number is this:
1234567890
Show to user this:
1,234,567,890
How can i write code that purpose?
I would suggest convert it to int (or long) first and then use ToString() and supply required format.
int number = int.Parse(numberString); //ex..
number.ToString("N0"); // 1,000,000
If you're asking about culture-specific formatting, then you could do this.
number.ToString("N0", CultureInfo.CreateSpecificCulture("es-US"));
You can explore more on standard numeric formats
Example code
Use the standard formatters and the CultureInfo for the desired country.
e.g
int i = int.Parse("123456");
string money = i.ToString("C", CultureInfo.CreateSpecificCulture("fr-Ir"));
Or if the system culture is fr-Ir
string money = i.ToString("C");
Which is the same as
string money = i.ToString("C", CultureInfo.CurrentCulture);
Or if you want to use the UI culture (the culture of the requesting browser)
string money = i.ToString("C", CultureInfo.CurrentUICulture);
Since you want to convert your value to currency, I would suggest using "C" of string formats provided by .NET.
123456.125M.ToString("C"); // $123,456.13
Sign infront of the string will be defined by the culture of your machine. More information here.
On the other hand, there is another solution to add your own custom format:
123456.125M.ToString("#,0.################"); // 123,456.125
It is not the clean way, but I have not since found a correct way of actually formating this in generic way.
Side note: for currency handling it is generally considered a good practise to use decimal. Since it does not have a floating point issue.
Please try this one hope will help
Just whats inside the void method
using System.Linq;
public class Program
{
public void ABC()
{
var data = "123456789";
const int separateOnLength = N;
var separated = new string(
data.Select((x,i) => i > 0 && i % separateOnLength == 0 ? new [] { ',', x } : new [] { x })
.SelectMany(x => x)
.ToArray()
);
}
}
I have written a small function in C# which isn't my main launguage so is coming across a little foreign to me.
public bool CheckForKey(string key)
{
string strKeyTime = Decode(key);
//valid key will be current time +- 5 minutes
string strTheTime = DateTime.Now.ToString("HH:mm:ss tt");
if (strKeyTime == strTheTime)
{
return true;
}
else
{
return false;
}
}
I need to alter this to allow for 5 minutes, so
if (strKeyTime == strTheTime)
needs to be
if (strKeyTime == strTheTime + or - 5 minutes)
my problem is matching the times as they are strings, perhaps convert key(original time) back to a date first and then do it, but I am pretty new to c#
If you convert (or keep) them both to DateTimes you can use TimeSpan:
TimeSpan delta = dateTime1 - dateTime2;
if (Math.Abs(delta.TotalMinutes) <= 5) { ... }
Look into using the DateTime.ParseExact (or any of the Parse... methods) to parse your strKeyTime, and then do something similar to the above.
To convert your sent string to the equivalent DateTime value, use the following code:
var keyDateTime = Convert.ToDateTime(strKeyTime);
var strTheTime = DateTime.Now
from here, you can use this value to compare with your original time value as the following:
if (keyDateTime == strTheTime || (keyDateTime > strTheTime && keyDateTime < strTheTime.AddMinutes(5))
{
return true;
}
the previous block of code will first check if we got an exact match, or the time sent to the method is between the original time and a time shift of additional 5 minutes.
that's it, if this is not what you need, let me know so I may update my answer for you, thanks.
-- if my answer is correct, don't forget to "Mark as answer".
"perhaps convert key(original time) back to a date first and then do it" sounds like a sound solution. I'd do it this way:
Convert both strings to DateTime instances.
Store difference in TimeSpan instance using DateTime.Subtract(DateTime value) ( http://msdn.microsoft.com/en-us/library/8ysw4sby.aspx )
Check if TimeSpanInstance.TotalMinutes is less than or equal to 5.
The first step is something I can't really give you any advice on without information concerning how your string is formatted. However, once this is done, the rest should be easy.
This is a tough one to phrase as a search query and I'm having no luck. And the more I think about it, it is more a logic question than a syntax one. However I am a newby to C# (8 years php) and I am currently building my third windows forms app so there may be a method built to do just what I want.
What I am doing is reading a date format given by the user as a single string and breaking it into parts to be assigned to an Array, or from what I have seen in my searches for Associative Arrays, maybe a SortedList or Dictionary.
e.g.
SortedList<string, int> resultArray = new SortedList<string, int>();
string dateFormat = "yyyyMMdd" // Just and example
int yearPos = dateFormat.IndexOf("yyyy");
int monthPos = dateFormat.IndexOf("MM");
int dayPos = dateFormat.IndexOf("dd");
resultArray.Add("yearPos", yearPos);
resultArray.Add("monthPos", monthPos);
resultArray.Add("dayPos", dayPos);
// So, resultArray expressed as an array looks like:
// resultArray["yearPos"] = 0
// resultArray["monthPos"] = 4
// resultArray["dayPos"] = 6
// Sort List and reassign keys (or values) based on their position value (which is unique)
// ???????
return resultArray;
Ideally, the finished result that I am after for this collection/array is to have the members ranked by the value of their position in the string. Like this:
// resultArray["yearPos"] = 1
// resultArray["monthPos"] = 2
// resultArray["dayPos"] = 3
The reason I am trying to do this, is because the same date format is used to pull out a real date from a file using Regex.Match. And I want to use these new values to know which group element of the match to use for each portion of the date.
Any help getting my head around this would be greatly appreciated.
I tried this and it works:
DateTime dt;
if (DateTime.TryParseExact("20110223", "yyyyMMdd", null, 0, out dt))
Console.WriteLine(dt);
Just use DateTime.TryParse. You can pass it a formatting string and it will do all the work for you.