|
And we come back to the same argument that has been presented to you many times - DON'T STORE YOU DATES AS STRINGS.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
Store the date as a date and your problem goes away altogether. A decision to use strings to represent dates is causing you unnecessary pain here; there's a DateTime datatype for a reason, use that. Think about it, you wouldn't store numbers as strings would you, so why store dates as strings?
|
|
|
|
|
Pete O'Hanlon wrote: you wouldn't store numbers as strings would you?
That may be a very brave assumption.
Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012
|
|
|
|
|
Hi,
I want to convert date formatted in yyyy/M/d to yyyy/MM/dd.
Is there any short way to do?
For example: 1400/6/7 to 1400/06/07
|
|
|
|
|
The first thing to clarify is whether you are dealing with a DateTime obtained by use of the Persian Calendar class: System.Globalization.PersianCalendar
... or, are you dealing with a run-time DateTime value on a computer where the OS is using the Persian Calendar as the default ?
Possible resources: Noda Time [^] and [^]
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
I use
System.Globalization.PersianCalendar
|
|
|
|
|
Okay, then is the formatting you want done on a machine using Persian Calendar as the default ?
If yes, then can't standard ToString Format syntax (as used in Farsi ?) give you what you want ?
DateTime dt = new DateTime(1400, 6, 7);
string fmt = dt.ToString("yyyy/MM/dd");
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Thanks, If I use this code to iterate through hundreds of datatable rows, would it consume more memory due to the instantiation?
|
|
|
|
|
DateTime is a value type, so it won't allocate anything on the heap.
The ToString call will allocate a string on the heap. But if you want to display the date to the user, then it has to be converted to a string at some point.
Without knowing precisely what you're trying to do, we can't really tell you how to optimise it.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: The ToString call will allocate a string on the heap. But if you want to display the date to the user, then it has to be converted to a string at some point. Hi, Richard, I am trying to understand this statement: I think you are making a distinction I am missing ... perhaps you are referring to (first) a pointer to the "raw bytes" on the heap ... compared to them bytes morphed into ascii format for display usage ?
Curious what you think of Skeet's format work-around for optimizing string conversion (link in my last message to Alex ... below).
As always, I look forward to your response.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
I was simply referring to the fact that a DateTime is a value type, whereas String is a reference type. Allocation of value types tends to be "cheaper" than reference types.
Jon's workaround is good, but could be improved in .NET Core 2.1, or even in .NET Framework 4.7.2+ with a reference to the System.Memory package and a couple of helpers defined.
#if NETSTANDARD2_0
namespace System.Buffers
{
public delegate void SpanAction<T, in TArg>(Span<T> span, TArg arg);
}
#endif
static class StringHelpers
{
public static string Create<TArg>(int length, TArg state, SpanAction<char, TArg> action)
{
if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));
if (action is null) throw new ArgumentNullException(nameof(action));
if (length == 0) return string.Empty;
#if NETSTANDARD2_0
unsafe
{
var str = new string('\0', length);
fixed (char* chars = str)
{
var span = new Span<char>(chars, length);
action(span, state);
}
return str;
}
#else
return string.Create(length, state, action);
#endif
}
}
public static string FormatDateTime(DateTime dt) => StringHelpers.Create(21, dt, static (buffer, date) =>
{
int value = date.Day;
buffer[0] = (char)('0' + (value / 10));
buffer[1] = (char)('0' + (value % 10));
buffer[2] = '.';
value = date.Month;
buffer[3] = (char)('0' + (value / 10));
buffer[4] = (char)('0' + (value % 10));
buffer[5] = '.';
value = date.Year;
buffer[6] = (char)('0' + ((value / 10) % 10));
buffer[7] = (char)('0' + (value % 10));
buffer[8] = ' ';
value = date.Hour;
buffer[9] = (char)('0' + (value / 10));
buffer[10] = (char)('0' + (value % 10));
buffer[11] = ':';
value = date.Minute;
buffer[12] = (char)('0' + (value / 10));
buffer[13] = (char)('0' + (value % 10));
buffer[14] = ':';
value = date.Second;
buffer[15] = (char)('0' + (value / 10));
buffer[16] = (char)('0' + (value % 10));
buffer[17] = ':';
value = date.Millisecond;
buffer[18] = (char)('0' + ((value / 100) % 10));
buffer[19] = (char)('0' + ((value / 10) % 10));
buffer[20] = (char)('0' + (value % 10));
}); Rather than allocating a new 21-character char array on every call, and then having the string constructor copy that array to its internal storage, this new version writes the values directly to the string 's internal storage. It does have to allocate a delegate for the SpanAction , but since it's a static lambda, that only happens once per AppDomain.
If you're using .NET Core 2.1 or later, or .NET 5, you can drop the helpers and just use string.Create directly.
Creating Strings with No Allocation Overhead Using String.Create - Steve Gordon - Code with Steve[^]
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
modified 22-Sep-21 5:23am.
|
|
|
|
|
Excellent ! I hope you'll publish this in an article, or a Tip/Trick.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
I think your code is missing the 'state' parameter.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
No - dt is the state parameter, and is referenced as date in the lambda method.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi, in the scope of your class StringHelpers: return string.Create(length, state, action); 'state is referenced, but is never defined. In the code in Steve Gordon's article, 'state is defined.
public static string Create<TState> (int length, TState state, System.Buffers.SpanAction<char,TState> action); My eyesight is terrible; as the doofus detective says in police procedural movies: "what am i missing ?"
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Whoops! The parameter arg should have been called state .
That should be fixed now.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Knowing you are not quite perfect makes me feel a little more secure, but, in no way diminishes my respect for your technical excellence
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
Alex Dunlop wrote: would it consume more memory due to the instantiation? Hi, I think to answer that clearly one would need to know the database, its internal format, etc., and the nature of your query that returns (I assume) some subset of rows. I don't have the expertise in this area to be more helpful.
But, yes, creating strings has a cost; here's an idea from uber-guru Jon Skeet you might try: [^]
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|
This is my data on which a LINQ query executed. i have bit confusion about LINQ grouping used there. here is sample code.
List<Data> _data = new List<Data>
{
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "ZB",
BrokerName = "B Securities",
Period = "2012 FYA",
PeriodValue = ""
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "2013 FYA",
PeriodValue = ""
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "1Q 2014A",
PeriodValue = "204.45"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "2Q 2014A",
PeriodValue = "205.00"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "2012 FYA",
PeriodValue = "101.33"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "2013 FYA",
PeriodValue = ""
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "1Q 2014A",
PeriodValue = "204.45"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Net Revenue",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "2Q 2014A",
PeriodValue = "201.00"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "2012 FYA",
PeriodValue = ""
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "2013 FYA",
PeriodValue = ""
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "1Q 2014A",
PeriodValue = "204.45"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "ZB",
BrokerName = "B. Riley Securities",
Period = "2Q 2014A",
PeriodValue = "201.00"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "2012 FYA",
PeriodValue = "101.33"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "2013 FYA",
PeriodValue = "222.30"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "1Q 2014A",
PeriodValue = "784.45"
},
new Data
{
Section = "Consensus Model",
Lineitem = "Cost of Goods Sold",
BrokerCode = "TU",
BrokerName = "Cantor Fitzgerald & Co",
Period = "2Q 2014A",
PeriodValue = "555.00"
},
};
var periods = _data.Select(y => y.Period).Distinct().OrderBy(y => y).ToArray();
var results =
_data
.GroupBy(
x => new { x.Section, x.Lineitem, x.BrokerCode, x.BrokerName },
x => new { x.Period, x.PeriodValue })
.Select(x => new
{
x.Key,
Lookup = x.ToLookup(y => y.Period, y => y.PeriodValue),
})
.Select(x => new
{
x.Key.Section,
x.Key.Lineitem,
x.Key.BrokerCode,
x.Key.BrokerName,
Map = periods.ToDictionary(y => y, y => String.Join("|", x.Lookup[y])),
})
.ToArray();
var dt = new DataTable();
dt.Columns.Add("Section");
dt.Columns.Add("Lineitem");
dt.Columns.Add("BrokerCode");
dt.Columns.Add("BrokerName");
foreach (var period in periods)
{
dt.Columns.Add(period);
}
foreach (var result in results)
{
string[] key_values = new string[]
{
result.Section,
result.Lineitem,
result.BrokerCode,
result.BrokerName,
};
string[] period_values = periods.Select(p => result.Map[p]).ToArray()
dt.Rows.Add(key_values.Concat(period_values).ToArray());
}
i have to group on few fields and those are Section, LineItem, BrokerCode and Period but a guy does the grouping like this way
var results =
_data
.GroupBy(
x => new { x.Section, x.Lineitem, x.BrokerCode, x.BrokerName },
x => new { x.Period, x.PeriodValue })
.Select(x => new
{
x.Key,
Lookup = x.ToLookup(y => y.Period, y => y.PeriodValue),
})
.Select(x => new
{
x.Key.Section,
x.Key.Lineitem,
x.Key.BrokerCode,
x.Key.BrokerName,
Map = periods.ToDictionary(y => y, y => String.Join("|", x.Lookup[y])),
})
.ToArray();
So my question is what kind of grouping is it.... see the below grouping code.
.GroupBy(
x => new { x.Section, x.Lineitem, x.BrokerCode, x.BrokerName },
x => new { x.Period, x.PeriodValue })
Is it two set of grouping ? one set is { x.Section, x.Lineitem, x.BrokerCode, x.BrokerName }
and another set is { x.Period, x.PeriodValue } ?
please guide me how the above grouping will be working ?
Thanks
|
|
|
|
|
|
Sir this kind of grouping still not clear.
GroupBy(
x => new { x.Section, x.Lineitem, x.BrokerCode, x.BrokerName },
x => new { x.Period, x.PeriodValue })
if it is one group then why there two x=> new{}
in first set they mention four fields name and in second set they mention two fields name.
still not clear the syntax how it is working. is it grouping on six fields ? if yes then developer could mention 6 fields name with in one
x=> new{x.Section, x.Lineitem, x.BrokerCode, x.BrokerName,x.Period, x.PeriodValue} ?
please help me to understand how these grouping is working. if possible please attach small sample code which explain how this grouping is working.
Thanks
|
|
|
|
|
Read the documentation again. The first parameter defines the object by which the list is grouped - the group's Key . The second parameter defines the type of objects within the group.
That GroupBy call will produce:
Group:
Key: { Section, Lineitem, BrokerCode, BrokerName }
Enumerable items:
{ Period, PeriodValue }
It is grouping on four fields, and projecting two fields for the items within each group.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Sir can you please provide me any good example which use the same kind of grouping. i search google but found not any similar LINQ grouping example code.
Thanks
|
|
|
|
|
Read the documentation!
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Stop trying to get other people to write your code for you, and start studying and experimenting.
«The mind is not a vessel to be filled but a fire to be kindled» Plutarch
|
|
|
|
|