Simply traditional foreach to Linq ForEach - c#

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().

Related

Filter a collection column by multiple values

I have a collection and I would like to filter it with one of the column contains multiple values. The filter values are dynamically generated and I dont know how many I will get.
I tried the following without success:
var input = #"was.Name.Contains(""Test"") || was.Name.Contains(""Test2"")";
var test = collection.Where(was => input)).ToList();
Assuming you receive the filter values as a CSV string:
var csvFilters = "Test1, Test2";
// split by ',', remove empty entries,
// trim each filter and store the result in a list
var filters = csvFilters.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(x => x.Trim())
.ToList();
// return items in collection whose Name property
// is equal to any of the items in filters
var result = collection.Where(x => filters.Contains(x.Name)).ToList();
This should translate to the following SQL:
SELECT * FROM collection c
WHERE c.Name IN ('Test1', 'Test2')
I guess you want to use LINQ. The question is, how the "filter" values are kept? I'll answer in the way I understand your question.
If input is supposed to be a condition then I'd suggest using Func<Object,bool>. This means, the input would be the condition you're looking for, and if found, it would return true.
Here is a simple example:
IEnumerable <T> FindElements (Func<Object, bool> condition, IEnumerable<T> inputList)
{
List<T> outputList = new List<T>();
foreach(var element in inputList)
{
if(condition != null && condition(element))
outputList.Add(element);
}
return outputList;
}
Then, if you call the function given exemplary parameters:
string input[] = {"Test1","Test2"};
foreach(string s in input)
{
targetList = FindElements(element=>((cast)element).Name.Contains(s), collection);
}
You should get all elements in collection which name has Test1 or Test2. Cast is of course name of the class which element instantiates.

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

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();

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>();

how to get string from string list?

I have list of string and there are number of string in the list.
Each string in the list start with number.
List<String> stringList=new List<String>();
stringList.Add("01Pramod");
stringList.Add("02Prakash");
stringList.Add("03Rakhi");
stringList.Add("04Test");
stringList.Add("04Test1");
stringList.Add("04Test2");
I want a Linq query that will return me list of string that starts with 04.
stringList.Where(s => s.StartsWith("04"))
or
stringList.Where(s => s.StartsWith("04")).ToList()
if you need a list
var result = stringList.Where(i => i.StartsWith("04"));
Here are the possible solution for it:
// Lambda
stringList.FindAll(o => o.StartsWith("04"));
// LINQ
(from i in stringList
where i.StartsWith("04")
select i).ToList();
I guess this will be easy to understand and its in proper format
var ss=from string g in stringList
where g.Substring(0,2)=="04"
select g;
foreach(string str in ss)
{
Console.WriteLine(str);
}

Categories