How to modify string list for duplicate values? - c#

I am working on project which is asp.net mvc core. I want to replace string list of duplicate values to one with comma separated,
List<string> stringList = surveylist.Split('&').ToList();
I have string list
This generate following output:
7=55
6=33
5=MCC
4=GHI
3=ABC
1003=DEF
1003=ABC
1=JKL
And I want to change output like this
7=55
6=33
5=MCC
4=GHI
3=ABC
1003=DEF,ABC
1=JKL
Duplicate items values should be comma separated.

There are probably 20 ways to do this. One simple one would be:
List<string> newStringList = stringList
.Select(a => new { KeyValue = a.Split("=") })
.GroupBy(a => a.KeyValue[0])
.Select(a => $"{a.Select(x => x.KeyValue[0]).First()}={string.Join(",", a.Select(x => x.KeyValue[1]))}")
.ToList();

Take a look at your output. Notice that an equal sign separates each string into a key-value pair. Think about how you want to approach this problem. Is a list of strings really the structure you want to build on? You could take a different approach and use a list of KeyValuePairs or a Dictionary instead.
If you really need to do it with a List, then look at the methods LINQ's Enumerable has to offer. Namely Select and GroupBy.
You can use Select to split once more on the equal sign: .Select(s => s.Split('=')).
You can use GroupBy to group values by a key: .GroupBy(pair => pair[0]).
To join it back to a string, you can use a Select again.
An end result could look something like this:
List<string> stringList = values.Split('&')
.Select(s => {
string[] pair = s.Split('=');
return new { Key = pair[0], Value = pair[1] };
})
.GroupBy(pair => pair.Key)
.Select(g => string.Concat(
g.Key,
'=',
string.Join(
", ",
g.Select(pair => pair.Value)
)
))
.ToList();
The group contains pairs so you need to select the value of each pair and join them into a string.

Related

Filtering and combining data in an array

I have an array:
{"Items":[
{"folder":"Test","number":"11"},
{"folder":"Test","number":"10"},
{"folder":"Test1","number":"130"},
{"folder":"Test1","number":"100"},
{"folder":"Test2","number":""},
{"folder":"Test2","number":"200"}
]}
Tell me I need to make it so that the folder is unique, and write its values in number separated by commas?
{"Items":[
{"folder":"Test","number":"11, 10"},
{"folder":"Test1","number":"130, 100"},
{"folder":"Test2","number":"200"}
]}
you could use GroupBy to group by folder and String.Join() to concatenate numbers, like :
var result = Items
.GroupBy(x => x.folder)
.Select(x => new
{
folder = x.Key,
number = string.Join(",", x.Select(y => y.number).Where(z => !string.IsNullOrEmpty(z)))
}).ToList();
Test in dotnetfiddle : https://dotnetfiddle.net/FDvSmc

How to do in this in Linq C#

So far, I have this:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)));
Configuration folder will contain pairs of files:
abc.json
abc-input.json
def.json
def-input.json
GetReportName() method strips off the "-input" and title cases the filename, so you end up with a grouping of:
Abc
abc.json
abc-input.json
Def
def.json
def-input.json
I have a ReportItem class that has a constructor (Name, str1, str2). I want to extend the Linq to create the ReportItems in a single statement, so really something like:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
**.Select(x => new ReportItem(x.Key, x[0], x[1]));**
Obviously last line doesn't work because the grouping doesn't support array indexing like that. The item should be constructed as "Abc", "abc.json", "abc-input.json", etc.
If you know that each group of interest contains exactly two items, use First() to get the item at index 0, and Last() to get the item at index 1:
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x)))
.Where(g => g.Count() == 2) // Make sure we have exactly two items
.Select(x => new ReportItem(x.Key, x.First(), x.Last()));
var v = Directory.EnumerateFiles(_strConfigurationFolder)
.GroupBy(x => GetReportName(Path.GetFileNameWithoutExtension(x))).Select(x => new ReportItem(x.Key, x.FirstOrDefault(), x.Skip(1).FirstOrDefault()));
But are you sure there will be exactly two items in each group? Maybe has it sence for ReportItem to accept IEnumerable, not just two strings?

Saving a split string to an arraylist using LINQ

I have some code that takes a string and processes it by splitting it into words, and giving the count of each word.
The trouble is it only returns void, because I am only able to print to the screen after the processing is done. Is there any way I can save the results in an arraylist, so that that I can return it to the method that called it?
The current code:
message.Split(' ').Where(messagestr => !string.IsNullOrEmpty(messagestr))
.GroupBy(messagestr => messagestr).OrderByDescending(groupCount => groupCount.Count())
.Take(20).ToList().ForEach(groupCount => Console.WriteLine("{0}\t{1}", groupCount.Key, groupCount.Count()));
Thank you.
Try this code
var wordCountList = message.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
.GroupBy(messagestr => messagestr)
.OrderByDescending(grp => grp.Count())
.Take(20) //or take the whole
.Select(grp => new KeyValuePair<string, int>(grp.Key, grp.Count()))
.ToList(); //return wordCountList
//usage
wordCountList.ForEach(item => Console.WriteLine("{0}\t{1}", item.Key, item.Value));
If you want, you can return the wordCountList which is a List<KeyValuePair<string, int>> containing all the words and their counts in descending order.
How you can use that, is also shown in the last line.
And rather than taking first 20 from the list, if you want to take the whole, remove this .Take(20) part.
First of all, by calling Take(20) you just take the first 20 words and put the others away. So, if you want all the results, remove it.
After that, you can do it like this:
var words = message.Split(' ').
Where(messagestr => !string.IsNullOrEmpty(messagestr)).
GroupBy(messagestr => messagestr).
OrderByDescending(groupCount => groupCount.Count()).
ToList();
words.ForEach(groupCount => Console.WriteLine("{0}\t{1}", groupCount.Key, groupCount.Count()));
To put the results into some other data structure, you can use one of these ways:
var w = words.SelectMany(x => x.Distinct()).ToList(); //Add this line to get all the words in an array
// OR Use Dictionary
var dic = new Dictionary<string, int>();
foreach(var item in words)
{
dic.Add(item.Key, item.Count());
}

IEnumerable<string> to Dictionary<char, IEnumerable<string>>

I suppose that this question might partially duplicate other similar questions, but i'm having troubles with such a situation:
I want to extract from some string sentences
For example from
`string sentence = "We can store these chars in separate variables. We can also test against other string characters.";`
I want to build an IEnumerable words;
var separators = new[] {',', ' ', '.'};
IEnumerable<string> words = sentence.Split(separators, StringSplitOptions.RemoveEmptyEntries);
After that, go throught all these words and take firs character into a distinct ascending ordered collection of characters.
var firstChars = words.Select(x => x.ToCharArray().First()).OrderBy(x => x).Distinct();
After that, go through both collections and for each character in firstChars get all items from words which has the first character equal with current character and create a Dictionary<char, IEnumerable<string>> dictionary.
I'm doing this way:
var dictionary = (from k in firstChars
from v in words
where v.ToCharArray().First().Equals(k)
select new { k, v })
.ToDictionary(x => x);
and here is the problem: An item with the same key has already been added.
Whis is because into that dictionary It is going to add an existing character.
I included a GroupBy extension into my query
var dictionary = (from k in firstChars
from v in words
where v.ToCharArray().First().Equals(k)
select new { k, v })
.GroupBy(x => x)
.ToDictionary(x => x);
The solution above gives makes all OK, but it gives me other type than I need.
What I should do to get as result an Dictionary<char, IEnumerable<string>>dictionary but not Dictionary<IGouping<'a,'a>> ?
The result which I want is as in the bellow image:
But here I have to iterate with 2 foreach(s) which will Show me wat i want... I cannot understand well how this happens ...
Any suggestion and advice will be welcome. Thank you.
As the relation is one to many, you can use a lookup instead of a dictionary:
var lookup = words.ToLookup(word => word[0]);
loopkup['s'] -> store, separate... as an IEnumerable<string>
And if you want to display the key/values sorted by first char:
for (var sortedEntry in lookup.OrderBy(entry => entry.Key))
{
Console.WriteLine(string.Format("First letter: {0}", sortedEntry.Key);
foreach (string word in sortedEntry)
{
Console.WriteLine(word);
}
}
You can do this:
var words = ...
var dictionary = words.GroupBy(w => w[0])
.ToDictionary(g => g.Key, g => g.AsEnumerable());
But for matter, why not use an ILookup?
var lookup = words.ToLookup(w => w[0]);

Split a LINQ string list

I believe this could be another easy one for you LINQ masters out there.
I have a table with a field that consists of strings delimited by "#". After I select the field using LINQ, how can I split each of the strings into a different list?
My string list looks like:
#A#B#C#D#G#F
I used a simple LINQ query to access this:
from x in Special_texts
where x.Name.Equals("ExceptionList")
select x.Content
In the end, my list should contain:
A
B
C
D
G
F
Thanks in advance.
Assuming you want a single list as output:
var list = Special_texts.Where(x=> x.Name.Equals("ExceptionList"))
.Select(x=> x.Content)
.AsEnumerable()
.Select(x=> x.Split(new [] {'#'}, StringSplitOptions.RemoveEmptyEntries))
.SelectMany(x=> x)
.ToList();
Alternatively if you want a list of lists (one for each item in Special_texts):
var list = Special_texts.Where(x=> x.Name.Equals("ExceptionList"))
.Select(x=> x.Content)
.AsEnumerable()
.Select(x=> x.Split(new [] {'#'}, StringSplitOptions.RemoveEmptyEntries).ToList())
.ToList();
from x in Special_texts
where x.Name.Equals("ExceptionList")
select x.Content.Split('#').ToList();

Categories