List<comma-separated strings> => List<string>? - c#

Trying to come up with a LINQy way to do this, but nothing's coming to me.
I have a List<> of objects which include a property which is a comma-separated list of alpha codes:
lst[0].codes = "AA,BB,DD"
lst[1].codes = "AA,DD,EE"
lst[2].codes = "GG,JJ"
I'd like a list of those codes, hopefully in the form of a List of strings:
result = AA,BB,DD,EE,GG,JJ
Thanks for any direction.

Use SelectMany to get all split codes and use Distinct to not repeat the values.
Try something like this:
var result = lst.SelectMany(x => x.codes.Split(",")).Distinct().ToList();

You need to use Split to split each string into multiple strings. Then you need to use SelectMany to concatenate multiple sequences into a single sequence, and then you need to use Distinct to remove duplicates.
var result =
lst
.SelectMany(x => x.codes.Split(','))
.Distinct()
.ToList();

if you need a string as a result:
string result = string.Join(",",lst.SelectMany(p=>p.codes.Split(",")).Distinct());

Try this:
List<string> list = new List<string>();
char[] sep = new char[1];
sep[0] = ',';
foreach (string item in lst)
{
list.AddRange(item.Split(sep));
}
list = list.Distinct().ToList();

Related

Simply traditional foreach to Linq ForEach

I have a list of strings like:
abcd#domain.com
efgh#domain.com
ijkl#domain.com;mnop#domain.com;qrst#domain.com
uvwx#domain.com
yz#domain.com
I would like to want it as:
abcd#domain.com
efgh#domain.com
ijkl#domain.com
mnop#domain.com
qrst#domain.com
uvwx#domain.com
yz#domain.com
So I wrote the code below and it works as expected.
foreach (var email in emailAddressesOnRequest)
{
if (!string.IsNullOrEmpty(email) && email.Contains(';'))
{
emailAddressesOnRequest.AddRange(email.Split(';').ToList());
emailAddressesOnRequest.Remove(email);
}
}
Is there any way to simply it to LINQ ForEach?
What you are looking for is to iterate through the collection and for each item to return an item of a different kind. For that use Select.
Because in your case you possibly want to return from each item a collection of items, and don't want to have them in nested collections use SelectMany on the result of the Split(';') method.
List<string> values = new List<string>
{
"abcd#domain.com",
"efgh#domain.com",
null,
"ijkl#domain.com; mnop #domain.com; qrst #domain.com",
"uvwx#domain.com",
"yz#domain.com"
};
var result = values.Where(value => !string.IsNullOrWhiteSpace(value))
.SelectMany(value => value.Split(';')).ToList();
And in query syntax:
var result = (from value in values
where !string.IsNullOrWhiteSpace(value)
from email in value.Split(';')
select email).ToList();
var query = from line in emailAddressesOnRequest
where !String.IsNullOrEmpty(line)
from email in line.Split(';')
select email;
What helped me a lot to understand ling was The standard LINQ operators
If you split each string into substrings by semicolon, you get a collection of string sequences, or an IEnumerable<IEnumerable<string>>
The IEnumareable extension function to convert them to an IEnumerable<string> is Enumerable.SelectMany. When iterating over a SelectMany it is like you do a nested foreach:
List<string[]> listOfStringArrays = ...
List<string> outputList = new List<string>();
foreach (string[] stringArray in listOfStringArrays)
{
foreach (string str in stringArray)
{
outputList.Add(str);
}
}
In your example the inner foreach is done using AddRange.
Using Select and Split you convert your collection of strings to a sequence of string sequences. SelectMany will make it a sequence of strings:
IEnumerable<string> myInputStrings = ...
IEnumerable<string> outputStrings = inputStrings
.Select(inputString => inputString.Split(';'))
.SelectMany(splitResult => splitResult);
The Select will take each of the inputStrings, and split them by semicolon. The output is a string array, which implements IEnumerable<string>, even if your input didn't have a semicolon.
The SelectMany concatenates every string sequence of you sequence of string sequences. The result is one sequence of strings.
To convert to array or list use ToArray() or ToList().

How can I remove numbers/digits from strings in a List<string>?

I have a List of strings:
List<string> _words = ExtractWords(strippedHtml);
_words contains 1799 indexes; in each index there is a string.
Some of the strings contain only numbers, for example:
" 2" or "2013"
I want to remove these strings and so in the end the List will contain only strings with letters and not digits.
A string like "001hello" is OK but "001" is not OK and should be removed.
You can use LINQ for that:
_words = _words.Where(w => w.Any(c => !Char.IsDigit(c))).ToList();
This would filter out strings that consist entirely of digits, along with empty strings.
_words = _words.Where(w => !w.All(char.IsDigit))
.ToList();
For removing words that are only made of digits and whitespace:
var good = new List<string>();
var _regex = new Regex(#"^[\d\s]*$");
foreach (var s in _words) {
if (!_regex.Match(s).Success)
good.Add(s);
}
If you want to use LINQ something like this should do:
_words = _words.Where(w => w.Any(c => !char.IsDigit(c) && !char.IsWhiteSpace(c)))
.ToList();
You can use a traditional foreach and Integer.TryParse to detect numbers.
This will be faster than Regex or LINQ.
var stringsWithoutNumbers = new List<string>();
foreach (var str in _words)
{
int n;
bool isNumeric = int.TryParse(str, out n);
if (!isNumeric)
{
stringsWithoutNumbers.Add(str);
}
}

Search for substring in an item of List

I have list :
List<string> str = new List<string>();
str.Add("asdf---US,IN");
str.Add("asdg---UK,IN");
str.Add("asjk---RU,IN");
str.Add("asrt---IT,DE");
I want to get List like ("asdf","asdg","asjk") when i enter "IN". For this i'm doing :
System.Text.RegularExpressions.Regex regEx =
new System.Text.RegularExpressions.Regex("asr",
System.Text.RegularExpressions.RegexOptions.IgnoreCase);
List<string> str = new List<string>();
str.Add("asdf---US,IN");
str.Add("asdg---UK,IN");
str.Add("asjk---RU,IN");
str.Add("asrt---IT,DE");
var getArray = str.Where<string>(item => regEx.IsMatch(item)).ToList<string>();
str = getArray.ToList();
str is having correct result. but it is containing whole item like "asdf---US,IN","asdg---UK,IN", "asjk---RU,IN". I only want first four character in item in list i.e., 'asdf", "asdg", "asjk". What condition can i put in lambda expression, to get list i want?
If its only going to be first four characters use string.SubString:
var getArray = str.Where(item => regEx.IsMatch(item))
.Select(r=> r.Substring(0,4))
.ToList();
You also doesn't need to specify <string> cast with where and ToList. Items in your list are already of type string.
EDIT:
If you are only looking for those strings that ends with "IN" you may get rid of the regex and use string.EndsWith:
var getArray = str.Where(item => item.EndsWith("IN"))
.Select(r=> r.Substring(0,4))
.ToList();
The regex should be
.*?(?=---.*?IN)
and the query should be
var getArray = str.Where<string>(item => regEx.IsMatch(item)).Select<string>(item => regEx.Match(item)).ToList<string>();

Get Count in List of instances contained in a string

I have a string containing up to 9 unique numbers from 1 to 9 (myString) e.g. "12345"
I have a list of strings {"1"}, {"4"} (myList) .. and so on.
I would like to know how many instances in the string (myString) are contained within the list (myList), in the above example this would return 2.
so something like
count = myList.Count(myList.Contains(myString));
I could change myString to a list if required.
Thanks very much
Joe
I would try the following:
count = mylist.Count(s => myString.Contains(s));
It is not perfectly clear what you need, but these are some options that could help:
myList.Where(s => s == myString).Count()
or
myList.Where(s => s.Contains(myString)).Count()
the first would return the number of strings in the list that are the same as yours, the second would return the number of strings that contain yours. If neither works, please make your question more clear.
If myList is just List<string>, then this should work:
int count = myList.Count(x => myString.Contains(x));
If myList is List<List<string>>:
int count = myList.SelectMany(x => x).Count(s => myString.Contains(s));
Try
count = myList.Count(s => s==myString);
This is one approach, but it's limited to 1 character matches. For your described scenario of numbers from 1-9 this works fine. Notice the s[0] usage which refers to the list items as a character. For example, if you had "12" in your list, it wouldn't work correctly.
string input = "123456123";
var list = new List<string> { "1", "4" };
var query = list.Select(s => new
{
Value = s,
Count = input.Count(c => c == s[0])
});
foreach (var item in query)
{
Console.WriteLine("{0} occurred {1} time(s)", item.Value, item.Count);
}
For multiple character matches, which would correctly count the occurrences of "12", the Regex class comes in handy:
var query = list.Select(s => new
{
Value = s,
Count = Regex.Matches(input, s).Count
});
try
var count = myList.Count(x => myString.ToCharArray().Contains(x[0]));
this will only work if the item in myList is a single digit
Edit: as you probably noticed this will convert myString to a char array multiple times so it would be better to have
var myStringArray = myString.ToCharArray();
var count = myList.Count(x => myStringArray.Contains(x[0]));

Get records which do not start with an alphabetical character in linq

I need to get a list of records that do not start with an alphabetical character, i.e. which either starts with a numerical character or any special character.
Whats the simple LINQ query to get this list?
List<string> Entries = new List<string>();
Entries.Add("foo");
Entries.Add("bar");
Entries.Add("#foo");
Entries.Add("1bar");
var NonAlphas = (from n in Entries
where !char.IsLetter(n.ToCharArray().First())
select n);
For Linq-to-sql you could hydrate your retrieval from the database by by enumerating the query (call ToList). From that point on, your operations will be against in-memory objects and those operations will not be translated into SQL.
List<string> Entries = dbContext.Entry.Where(n => n.EntryName).ToList();
var NonAlphas = Entries.Where(n => !char.IsLetter(n.First()));
Something like this?
List<string> lst = new List<string>();
lst.Add("first");
lst.Add("second");
lst.Add("third");
lst.Add("2abc");
var result = from i in lst where !char.IsLetter(i[0]) select i;
List<string> output = result.ToList();
Edit: I realized that using Regex here was overkill and my solution wasn't perfect anyway.
string[] x = new string[3];
x[0] = "avb";
x[1] = "31df";
x[2] = "%dfg";
var linq = from s in x where !char.IsLetter(s.ToString().First()) select s;
List<string> simplelist = new List<string>(linq);
/* in simple list you have only "31df" & "dfg" */
One thing to note is that you don't need to convert the string to a chararray to use linq on it.
The more consise version would be:
var list = new List<string> {"first","third","second","2abc"};
var result = list.Where(word => !char.IsLetter(word.First()));

Categories