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