2013-08-05 4 views
1

Есть в любом случае, чтобы написать свою очередь, это для каждого цикла в выражение Linq:Включение Еогеасп петли для Linq

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

Мой следующий вопрос заключается в том, действительно с помощью Linq выражений вместо скорости цикла Еогеасп до производительность программы , Я немного новый для этого linq.

Обновление: Использование слишком большого числа циклов foreach замедляет мою программу.

+0

не уверен, что linq может увеличить скорость. Но несколько строк – Shyju

+2

Linq на самом деле [гораздо медленнее] (http://ox.no/posts/linq-vs-loop-a-performance-test), чем не-linq-код – Tyrsius

+0

Я использую слишком много циклов foreach и они действительно замедляют мою программу, поэтому я ищу более эффективный способ сделать это быстрее. – Transcendent

ответ

6

Использование выражения linq вместо цикла foreach ускоряет работу программы, я как бы новичок в этом linq.

Нет. Внутренне LINQ будет по-прежнему выполнять одинаковое количество итераций, поэтому, в общем, он не ускорит работу. Правильно написано, LINQ будет работать так же, как и цикл.

Очень полезно сделать намерение более ясным, что в свою очередь иногда упрощает оптимизацию и сокращение короткого замыкания. При этом те же самые оптимизации можно делать на петлях так же легко.

Есть в любом случае, чтобы написать свою очередь, это для каждого цикла в выражение Linq:

Да. Это может быть сделано с помощью:

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

Обратите внимание, что внутренний корпус/петли слева как foreach цикла, с целью, в данном случае, как это выполняет побочные эффекты.

Учитывая, что кажется, вы список и набор здание, вы можете использовать:

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

Это обеспечит вам набор уникальных значений (как HashSet<string>), а также список значений. Если вам просто нужен уникальный список значений, вы можете использовать Distinct построить непосредственно:

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

Если вам нужен словарь, то это просто принимает эти результаты:

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

Большое спасибо, я думаю, что получил свой ответ :). – Transcendent

+0

Это не гарантирует уникальность. Используйте HashSet или '.Distinct()'. – SLaks

+0

Я не думаю, что результат будет таким же. – MarcinJuraszek

1

здесь некрасиво 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); 
    } 
1
List<string> itemList = this.datasetItemset 
    .SelectMany(item => item.Split(' ')) 
    .Distinct() 
    .ToList(); 

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

Что касается производительности, Linq будет медленнее, чем тщательно продуманной конкретных но он обычно достаточно быстр. Если производительность является для вас проблемой, вы, вероятно, должны ее избегать (после профилирования).

+0

@MarcinJuraszek - Хорошо, что вы можете создать 'itemList' с нетерпением – Lee

0

Вы можете легко сделать то же самое с помощью LINQ:

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

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

Тем не менее, все еще foreach петли скрыты внутри SelectMany, Distinct, ToList и ToDictionary методов. Здесь нет волшебства! Дополнительные вызовы делегатов делают это медленнее, чем пользовательские циклы.

+0

Накладные расходы делегатов не слишком значительны. Также обратите внимание, что реализация «Distinct» значительно лучше, чем алгоритм OP, что приведет к значительному улучшению производительности, скорее всего, больше, чем накладные расходы делегатов, если для начала достаточно данных для производительности. – Servy

+0

@Servy Вы правы.'HashSet', используемый' Distinct', намного лучше, чем 'Contains', поэтому было бы лучше, чем его текущее решение. @AustinSalonen Он уже отредактировал свой ответ. Я критикую предыдущую версию. – MarcinJuraszek

1

Вот как я бы выписывать этот код:

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

Это более идиоматический LINQ способ решения этой проблемы.

вложенной Еогеасп обычно сопоставляется с SelectMany вызова, и вместо того, чтобы проверить, если элемент уже существует Вы можете использовать Distinct, который не только семантически представляет то, что вы пытаетесь сделать, но будет заметно более эффективным (как вы избегая повторных линейных поисков через список, вы можете использовать HashSet для более эффективного поиска в решении, отличном от LINQ, если хотите). Вместо того, чтобы добавлять элементы в коллекции, вы можете преобразовать каждую последовательность непосредственно в коллекцию с использованием ToList и ToDictionary, чтобы избежать явного использования foreach.

Смежные вопросы