Вызывая собирателей кода - альтернативы вложенным циклам - PullRequest
8 голосов
/ 13 декабря 2008

Для меня (или, вероятно, для кого-то еще) весьма свойственно иметь список объектов, которые мне нужно перебрать, а затем взаимодействовать со списком свойств. Я использую вложенный цикл, например:

IList<T> listOfObjects;
IList<TProperty> listOfProperties;

foreach (T dataObject in listOfObjects)
{
    foreach (TProperty property in listOfProperties)
    {
        //do something clever and extremely useful here
    }
}

Является ли этот шаблон проверенным временем и производительностью для этой проблемы? Или есть что-то более производительное, более элегантное или просто забавное (хотя, конечно, читаемое и обслуживаемое)?

Код выше не заставляет меня улыбаться. Может кто-нибудь помочь принести радость моей петле?

Спасибо!

Обновление: я использую термин "ботаник" в наиболее позитивном смысле. Как часть определения в Википедии, это означает, что «это относится к человеку, который страстно занимается интеллектуальной деятельностью». Под «ботаником кода» я подразумеваю того, кто обеспокоен постоянным совершенствованием себя как программиста, поиском новых, новых и элегантных способов кодирования, которые бывают быстрыми, легко обслуживаемыми и красивыми! Они радуются выходу из VB6 и хотят, чтобы умные люди критиковали свой код и помогали им самим себя почувствовать. (Примечание: им также нравится создавать новые слова, оканчивающиеся на -ify).

Конечная нота:

Спасибо Dave R, Earwicker и TheSoftwareJedi за то, что отправили меня по пути Linq. Это просто тот счастливый код, который я искал!

Ответы [ 8 ]

8 голосов
/ 13 декабря 2008

Похоже, вы пытаетесь декартово объединить два списка и применить предложение where. Вот простой пример, показывающий синтаксис Linq для этого, и я думаю, это то, что вы ищете. list1 и list2 могут быть любым IEnumerable, ваше предложение where может содержать более подробную логику, а в предложении select вы можете найти то, что вам нужно.

        var list1 = Enumerable.Range(1, 100);
        var list2 = Enumerable.Range(1, 100);

        foreach (var item in from a in list1
                             from b in list2
                             where a % b == 0
                             select new { a, b })
        {
            Console.WriteLine(item);
        };

Производительность будет идентична той, которую вы опубликовали, - нет никакого желания вводить в заблуждение по этому поводу. Я предпочитаю этот синтаксис Linq.

8 голосов
/ 13 декабря 2008

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

Если вы хотите выполнять действия, выполняя итерацию по коллекции, вы можете обнаружить, что LINQ будет интересным способом изучения:

http://msdn.microsoft.com/en-us/vcsharp/aa904594.aspx

Вы будете ограничивать себя более поздними версиями Framework (начиная с 3.5), но на самом деле подход функционального программирования может показаться вам довольно элегантным. Другие языковые функции, которые вступают в игру, когда вы идете по этому пути, включают лямбды и анонимные методы, которые сами по себе очаровательны.

Желаю удачи, и я надеюсь, что вы повеселитесь в пути - это отличный подход:)

5 голосов
/ 13 декабря 2008
foreach (var pair in from obj in listOfObjects
                     from prop in listOfProperties  
                     select new {obj, prop})
{
   Console.WriteLine(pair.obj + ", " + pair.prop);
}
3 голосов
/ 13 декабря 2008

Если вам нужно что-то сделать с каждым объектом и каждым свойством, делать не так много. Возможно, вы сможете делать некоторые синтаксически приятные вещи, но нет способа обойти эту работу.

Если вы работаете только с подмножеством объектов и / или свойств, отфильтруйте его (с linq для объектов, если вы делаете .net 3.5)!

Вам может понравиться Фильтр / Карта / Уменьшение для ваших наборов как средство введения лучшего синтаксиса для выполнения операций над множествами.

2 голосов
/ 15 декабря 2008

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

foreach(dataObject in listOfObjects)
    DoSomethingCleverWithProperties(dataObject, listOfProperties);

Мне это кажется более понятным.

2 голосов
/ 15 декабря 2008
Action<T, TProp> somethingClever = //your clever method

listOfObjects
  .SelectMany(
    o => listOfProperties,
    (o, p) => new {o, p})
  .ToList()
  .ForEach(x => somethingClever(x.o, x.p));
0 голосов
/ 15 декабря 2008

Мне нравятся каналы и фильтры Ayende , но это гораздо больше кода, чем встроенный LINQ для простых циклов (я предполагаю, что пример кода в вопросе был тривиальным).

0 голосов
/ 13 декабря 2008

В таком сценарии мы часто начинаем с фильтрации интересующих нас фрагментов. Ваш блок dosomethingclever () обычно начинается в

foreach (T dataObject in listOfObjects)
{    
  foreach (TProperty property in listOfProperties)    
  {
    if (property.something == "blah") 
    { // OK, we found the piece we're interested in...

      // do something clever...

    }
  }
}

Здесь LINQ - ваш друг, позволяющий вам заменить свои циклы оператором select. Конечно, вам все еще может потребоваться выполнить итерацию набора результатов.

Тонны образцов здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...