I have the following string in c#
Count([AssignedTo]) as [AssignedTo] , Sum([Billing Amount]) as [Billing Amount] , Max([Billing Rate]) as [Billing Rate] , Min([ExecutionDate]) as [ExecutionDate] , Average([HoursSpent]) as [HoursSpent] , [Project], [Sub-Project], [TaskName], [Vendor], [Work Classification], [Work Done], Count([WorkItemType]) as [WorkItemType]
Now I want list of all fields having aggregate function , through string manipulation or linq
output like
Count([AssignedTo])
Sum([Billing Amount])
Max([Billing Rate])
Min([ExecutionDate])
Average([HoursSpent])
Count([WorkItemType])
Perhaps this works for you:
var aggr = new []{ "Count", "Sum", "Max", "Min", "Average"};
var allAggregates = text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(col => new{ col, token = col.TrimStart().Split().First() })
.Where(x => x.token.Contains('(') && aggr.Any(a => x.token.StartsWith(a, StringComparison.OrdinalIgnoreCase)))
.Select(x => x.token);
DEMO
can i get the field name only which is inside function
I prefer string methods instead of regex if possible:
var allAggregates = text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(col => new { col, token = col.TrimStart().Split().First() })
.Where(x => x.token.Contains('(') && aggr.Any(a => x.token.StartsWith(a, StringComparison.OrdinalIgnoreCase)))
.Select(x => {
string innerPart = x.token.Substring(x.token.IndexOf('(') + 1);
int index = innerPart.IndexOf(')');
if (index >= 0)
innerPart = innerPart.Remove(index);
return innerPart;
});
var aggregates = new []{ "Count", "Sum", "Max", "Min", "Average"};
var output=Regex.Matches(input,#"(\w+)\(.*?\)")
.Cast<Match>()
.Where(x=>aggregates.Any(y=>y==x.Groups[1].Value))
.Select(z=>z.Value);
This is another way:
string[] funcNames = new string[]{"Sum","Average","Count","Max","Min"};
string s = "Your String";
var output = from v in s.Split(',')
where funcNames.Contains(v.Split('(')[0].Trim())
select v.Split(new string[]{" as "},
StringSplitOptions.RemoveEmptyEntries)[0].Trim();
.Split('(')[1].Split(')')[0]; //this line is to get only field names
//Print results
foreach(var str in output) Console.WriteLine(str);
Related
I have a file with content like below,
2018-02-28 10:00:00,A1, A2
2018-02-28 10:05:00,A3, A4
2018-02-28 10:10:00,A5, A6
2018-02-28 10:00:00,A7, A8
Now I would like get all the file content (as a different file) from date/time greater than 2018-02-28 10:05:00?
I am able to check modified files after certain data,
var files = directory.GetFiles().Where(file=>file.LastWriteTime >= datetine.now);
But how to get content ?
You can use this (using C#7 out variable feature):
var fileContents = directory.GetFiles()
.Select(f => new
{
File = f,
Content = File.ReadLines(f.FullName)
.Select(l => new{ Line = l, Fields = l.Split(',') })
.Select(x => new
{
x.Line, x.Fields,
DateStr = x.Fields[0].Trim(),
IsValid = DateTime.TryParse(x.Fields[0].Trim(), out var date),
Date = date
})
.Where(x => x.IsValid && x.Date > DateTime.Now)
.ToArray()
});
Try following
string input = "2018-02-28 10:00:00,A1, A2\n" +
"2018-02-28 10:05:00,A3, A4\n" +
"2018-02-28 10:10:00,A5, A6\n" +
"2018-02-28 10:00:00,A7, A8";
DateTime now = DateTime.Now;
var results = input.Split(new string[] { "\n" }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries))
.Select( y => new { date = DateTime.Parse(y.First()), colA = y.Skip(1).First(), colB = y.Last() })
.Where(x => x.date <= now).ToList();
For example :
this array:
a 2
a 10
a
should be after sort :
a
a 2
a 10
I try this, but it doesn't not work: the order is wrong.
...
.OrderBy(s => s.name)
.ThenBy(s => {
var stringNumber = Regex.Match(s.name, #"\d+").Value;
return string.IsNullOrEmpty(stringNumber)
? 0
: int.Parse(stringNumber);
});
I suggest extracting criterium explicitly: name and number groups in the regular expression:
var list = new List<string>() {
"a",
"a 4",
"b 1",
"a 2",
"a 11"
};
var result = list
.Select(item => new {
value = item,
match = Regex.Match(item, #"^(?<name>.*?)\s*(?<number>[0-9]*)$"),
})
.OrderBy(item => item.match.Groups["name"].Value)
.ThenBy(item => item.match.Groups["number"].Value.Length)
.ThenBy(item => item.match.Groups["number"].Value)
.Select(item => item.value);
Test:
Console.WriteLine(string.Join(Environment.NewLine, result));
Outcome:
a
a 2
a 4
a 11
b 1
Since you said "letter" I assume you want to only sort by the first character, then by the number.
So don't OrderBy the whole string, but by the letter only:
var result = list
.OrderBy(s => s.FirstOrDefault()) // only first character
.ThenBy(s =>
{
var stringNumber = Regex.Match(s.name, #"\d+").Value;
return string.IsNullOrEmpty(stringNumber) ? 0 : int.Parse(stringNumber);
})
Your code sorted by the whole string at first, so ThenBy had no effect anymore.
You could try something like that;
var list = new List<string>()
{
"a ",
"a 4",
"b 1",
"a 2"
};
int value = 0;
list = list
.Select(x => new {
WholeString = x,
StringPart = x.Split(' ')[0],
IntPart = int.TryParse(x.Split(' ')[1], out value) ? value : 0
})
.OrderBy(x => x.StringPart)
.ThenBy(x => x.IntPart)
.Select(x => x.WholeString)
.ToList();
var test = new[] {"a 2", "a 10", "a"};
var sorted = test.OrderBy(s => new string(s.Where(char.IsLetter).ToArray())).ThenBy(s =>
{
var stringNumber = Regex.Match(s, #"\d+").Value;
return string.IsNullOrEmpty(stringNumber) ? 0 : int.Parse(stringNumber);
});
This should sort by letters first, then by numbers.
I have a list of string and I want to make every string in that list unique by appending a number at the end of it. Also, it is case insensitive, so "apple" should be assumed the SAME as "Apple" or "apPlE"
For example:
List<string> input = new List<string>();
input.Add("apple");
input.Add("ball");
input.Add("apple");
input.Add("Apple");
input.Add("car");
input.Add("ball");
input.Add("BALL");
Expected output:
"apple", "ball", "apple2", "Apple3", "car", "ball2", "BALL3"
I need help to develop the logic to produce the output. Thank you.
Edited: I CANNOT have 0 and 1, the repeated string must start with 2, 3, 4...
var newList = input.GroupBy(x => x.ToUpper())
.SelectMany(g => g.Select((s, i) => i == 0 ? s : s + (i+1)))
.ToList();
var str = String.Join(", ", newList);
EDIT
var newList = input.Select((s, i) => new { str = s, orginx = i })
.GroupBy(x => x.str.ToUpper())
.Select(g => g.Select((s, j) => new { s = j == 0 ? s.str : s.str + (j + 1), s.orginx }))
.SelectMany(x => x)
.OrderBy(x => x.orginx)
.Select(x => x.s)
.ToList();
I have a stringbuilder output as
(AnimalAge;Dog:20,Cat:10,Rat:5#\r\nAnimalType;Whale:Mammal,Crocodile:Reptile#\r\n)
I want to have AnimalAge as different entity and AnimalType as a different output.
How do i separate these values so that i can populate this in different textboxes\labels?
I didn't optimize the code, but it should look like
var text = new StringBuilder("AnimalAge;Dog:20,Cat:10,Rat:5#\r\nAnimalType;Whale:Mammal,Crocodile:Reptile#\r\n");
var cat = text.ToString().Split(new[] { "#\r\n" }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split(new[] { ";" }, StringSplitOptions.None))
.Select(x => new
{
Category = x[0],
Values = x[1].Split(new[] { "," }, StringSplitOptions.None)
})
.Select(x => new
{
Category = x.Category,
Values = x.Values.ToDictionary(y => y.Split(new[] { ":" }, StringSplitOptions.None)[0], y => y.Split(new[] { ":" }, StringSplitOptions.None)[1])
})
.ToList();
In the end you will get a list of Category/Values object, where Values is a Dictionary
I have this string
string sx="(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
and am splitting it with
string [] ss=sx.Split(new char[] { '(', ')' },
StringSplitOptions.RemoveEmptyEntries);
Instead of that, how could I split the result into a Dictionary<string,string>? The
resulting dictionary should look like:
Key Value
colorIndex 3
font.family Helvetica
font.bold 1
It can be done using LINQ ToDictionary() extension method:
string s1 = "(colorIndex=3)(font.family=Helvicta)(font.bold=1)";
string[] t = s1.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, string> dictionary =
t.ToDictionary(s => s.Split('=')[0], s => s.Split('=')[1]);
EDIT: The same result can be achieved without splitting twice:
Dictionary<string, string> dictionary =
t.Select(item => item.Split('=')).ToDictionary(s => s[0], s => s[1]);
There may be more efficient ways, but this should work:
string sx = "(colorIndex=3)(font.family=Helvicta)(font.bold=1)";
var items = sx.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Split(new[] { '=' }));
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (var item in items)
{
dict.Add(item[0], item[1]);
}
Randal Schwartz has a rule of thumb: use split when you know what you want to throw away or regular expressions when you know what you want to keep.
You know what you want to keep:
string sx="(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
Regex pattern = new Regex(#"\((?<name>.+?)=(?<value>.+?)\)");
var d = new Dictionary<string,string>();
foreach (Match m in pattern.Matches(sx))
d.Add(m.Groups["name"].Value, m.Groups["value"].Value);
With a little effort, you can do it with ToDictionary:
var d = Enumerable.ToDictionary(
Enumerable.Cast<Match>(pattern.Matches(sx)),
m => m.Groups["name"].Value,
m => m.Groups["value"].Value);
Not sure whether this looks nicer:
var d = Enumerable.Cast<Match>(pattern.Matches(sx)).
ToDictionary(m => m.Groups["name"].Value,
m => m.Groups["value"].Value);
string sx = "(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
var dict = sx.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Split('='))
.ToDictionary(x => x[0], y => y[1]);
var dict = (from x in s1.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
select new { s = x.Split('=') }).ToDictionary(x => x[0], x => x[1]);
Often used for http query splitting.
Usage: Dictionary<string, string> dict = stringToDictionary("userid=abc&password=xyz&retain=false");
public static Dictionary<string, string> stringToDictionary(string line, char stringSplit = '&', char keyValueSplit = '=')
{
return line.Split(new[] { stringSplit }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Split(new[] { keyValueSplit })).ToDictionary(x => x[0], y => y[1]); ;
}
You can try
string sx = "(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
var keyValuePairs = sx.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
.Select(v => v.Split('='))
.ToDictionary(v => v.First(), v => v.Last());
You could do this with regular expressions:
string sx = "(colorIndex=3)(font.family=Helvetica)(font.bold=1)";
Dictionary<string,string> dic = new Dictionary<string,string>();
Regex re = new Regex(#"\(([^=]+)=([^=]+)\)");
foreach(Match m in re.Matches(sx))
{
dic.Add(m.Groups[1].Value, m.Groups[2].Value);
}
// extract values, to prove correctness of function
foreach(var s in dic)
Console.WriteLine("{0}={1}", s.Key, s.Value);
I am just putting this here for reference...
For ASP.net, if you want to parse a string from the client side into a dictionary this is handy...
Create a JSON string on the client side either like this:
var args = "{'A':'1','B':'2','C':'" + varForC + "'}";
or like this:
var args = JSON.stringify(new { 'A':1, 'B':2, 'C':varForC});
or even like this:
var obj = {};
obj.A = 1;
obj.B = 2;
obj.C = varForC;
var args = JSON.stringify(obj);
pass it to the server...
then parse it on the server side like this:
JavaScriptSerializer jss = new JavaScriptSerializer();
Dictionary<String, String> dict = jss.Deserialize<Dictionary<String, String>>(args);
JavaScriptSerializer requires System.Web.Script.Serialization.