Transcendent
Transcendent

Reputation: 5745

Turning foreach loops to Linq

Is there anyway to write turn this for each loop into Linq expression:

private List<string> datasetItemset;
Dictionary<string, int> itemsetScanning = new Dictionary<string, int>();
List<string> itemList = new List<string>();
foreach (string transaction in this.datasetItemset)
{
    string[] items = transaction.Split(new char[] { ' ' });
    foreach (string item in items)
        if (!itemList.Contains(item))
        {
            itemList.Add(item);
            itemsetScanning.Add(item, 0);
        }
}

My next question is that , does using linq expressions instead of foreach loop speed up the performance of the program, I'm kind of new to this linq.

Update: Using too many foreach loop is slowing down my program.

Upvotes: 1

Views: 836

Answers (5)

Reed Copsey
Reed Copsey

Reputation: 564323

does using linq expressions instead of foreach loop speed up the performance of the program, I'm kind of new to this linq.

No. Internally, LINQ will still typically perform the same number of iterations, so in general, it won't speed things up. Written properly, LINQ will perform very similarly to the looping.

It is very useful to make the intent more clear, which in turn can sometimes make it simpler to optimize and short curcuit. That being said, those same optimizations can be done on loops just as easily.

Is there anyway to write turn this for each loop into Linq expression:

Yes. This could be done via:

foreach(var item in this.datasetItemset
   .SelectMany(transaction => transaction.Split(' '))
   .Distinct())
{
    itemList.Add(item);
    itemsetScanning.Add(item, 0);
}

Note that the inner body/loop is left as a foreach loop, on purpose, in this case, as it's performing side effects.

Given that it appears you're building list and a set, you could use:

var itemList = this.datasetItemset.SelectMany(transaction => transaction.Split(' ')).ToList();
var uniqueSet = new HashSet<string>(itemList); // Build the set from the list

This would provide you a set of unique values (as a HashSet<string>) as well as the list of values. If you just need a unique list of values, you can use Distinct to build it directly:

 var uniqueItemList = this.datasetItemset
                          .SelectMany(transaction => transaction.Split(' '))
                          .Distinct()
                          .ToList();

If you need the dictionary, then it's merely taking these results:

var itemsetScanning = uniqueItemList.ToDictionary(i => i, i => 0);

Upvotes: 6

Servy
Servy

Reputation: 203802

Here's how I would write out that code:

var itemList = datasetItemset.SelectMany(transaction => transaction.Split(' '))
    .Distinct()
    .ToList();
var itemsetScanning = itemList.ToDictionary(transaction => transaction,
    transaction => 0);

This is the more idiomatic LINQ way of addressing the problem.

The nested foreach generally maps to a SelectMany call, and rather than checking if the item already exists you can use Distinct, which not only semantically represents what you're trying to do, but will be noticeably more efficient (as you're avoiding repeated linear searches through a list; you could use a HashSet to more efficiently search in a non-LINQ solution if you wanted). Rather than adding the items to collections, you can instead convert each sequence directly into a collection using ToList and ToDictionary, to avoid explicitly using a foreach.

Upvotes: 1

Lee
Lee

Reputation: 144126

List<string> itemList = this.datasetItemset
    .SelectMany(item => item.Split(' '))
    .Distinct()
    .ToList();

var itemsetScanning = itemList.ToDictionary(e => e, _ => 0);

Regarding performance, Linq will be slower than a carefully-crafted specific solution, but it is usually quick enough. If performance is an issue for you, you should probably avoid it (after profiling).

Upvotes: 1

MarcinJuraszek
MarcinJuraszek

Reputation: 125610

You can easily do the same using LINQ:

var itemList = this.datasetItems
                   .SelectMany(x => x.split(' '))
                   .Distinct()
                   .ToList();

var itemssetScanning = itemList.ToDictionary(x => x, x => 0);

However, there still are foreach loops hidden inside SelectMany, Distinct, ToList and ToDictionary methods. There is no magic here! Additional delegates calls makes it slower then custom loops.

Upvotes: 0

Jonesopolis
Jonesopolis

Reputation: 25370

here is ugly linq

foreach (var item in this.datasetItemset
    .Select(transaction => transaction.Split(new char[] { ' ' }))
    .SelectMany(items => items
        .Where(item => !itemList.Contains(item))))
    {
        itemList.Add(item);
        itemsetScanning.Add(item, 0);
    }

Upvotes: 1

Related Questions