good-to-know
good-to-know

Reputation: 742

Simply traditional foreach to Linq ForEach

I have a list of strings like:

[email protected]
[email protected]
[email protected];[email protected];[email protected]
[email protected]
[email protected]

I would like to want it as:

[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]

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?

Upvotes: 1

Views: 379

Answers (3)

Gilad Green
Gilad Green

Reputation: 37299

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>
{
    "[email protected]",
    "[email protected]",
    null,
    "[email protected]; mnop @domain.com; qrst @domain.com",
    "[email protected]",
    "[email protected]"
};

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

Upvotes: 5

Harald Coppoolse
Harald Coppoolse

Reputation: 30454

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

Upvotes: 1

qxg
qxg

Reputation: 7036

var query = from line in emailAddressesOnRequest
            where !String.IsNullOrEmpty(line)
            from email in line.Split(';')
            select email;

Upvotes: 1

Related Questions