Разделить список объектов

1

Итак, вот мой код:

private List<IEnumerable<Row>> Split(IEnumerable<Row> rows, 
                                     IEnumerable<DateTimePeriod> periods) 
{
    List<IEnumerable<Row>> result = new List<IEnumerable<Row>>();

    foreach (var period in periods) 
    {
        result.Add(rows.Where(row => row.Date >= period.begin && row.Date <= period.end));
    }

    return result;
}

private class DateTimePeriod 
{
    public DateTime begin { get; set; }
    public DateTime end { get; set; }
}

Как вы можете видеть, этот код не самый лучший, он выполняет итерацию по всем строкам за каждый период. Мне нужен совет по оптимизации этого кода. Возможно, для этого существуют подходящие Перечислимые методы?

Обновление: все строки и периоды, упорядоченные по дате, и все строки всегда находятся в одном из этих периодов.

  • 0
    Можете ли вы объяснить немного больше, что именно вы пытаетесь сделать?
  • 0
    Вы получите много повторяющихся строк, верно? Тебя не волнует, какой период условия строки удовлетворены?
Показать ещё 8 комментариев
Теги:
ienumerable

3 ответа

2
Лучший ответ

Более быстрый метод состоял бы в том, чтобы выполнить объединение в двух структурах, однако Linq поддерживает только equi-соединения (объединения, где два выражения равны). В вашем случае вы присоединяетесь к одному значению, находящемуся в диапазоне значений, поэтому equi-join невозможен.

Прежде чем приступать к оптимизации, убедитесь, что он нуждается в оптимизации. Будет ли ваша программа значительно быстрее, если эта функция будет быстрее? Сколько времени на ваше приложение тратится на эту функцию?

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

Тем не менее, поскольку вы говорите, что строки и периоды уже отсортированы по дате, вы можете получить некоторую выгоду от производительности, используя циклы, прокручивая строки до тех пор, пока не выйдете из текущего периода, а затем перейдете к следующему периоду. По крайней мере, вы не перечислите rows (или periods) несколько раз.

1

В вашем коде есть небольшая проблема: rows IEnumerable так что их можно перечислить несколько раз. в foreach. Это хорошая идея, чтобы изменить его на нечто более стабильное, например массив, вне поля foreach:

var myRows = rows as Row[] ?? rows.ToArray();

Кстати. Я изменил код следующим кодом, используя Resharper:

var myRows = rows as Row[] ?? rows.ToArray();
return periods.Select(period => myRows.Where(row => row.Date >= period.begin && row.Date <= period.end)).ToList();
  • 1
    Ваш первый пункт неверен - многократное перечисление массива не лучше, чем многократное перечисление List или другой перечислимой коллекции. Вам нужно изменить метод или перечисление, а не структуру данных .
  • 1
    @DStanley Перечисляя Массив несколько раз лучше , чем перечислив L2S-запрос или EF запрос. IEnumerable<Row> может быть IQueryable<Row> . Я думаю, что ОП надеялся на большее, но я думаю, что это все еще верный момент.
0

Ваш лучший шанс оптимизировать алгоритм O(nxm) - это преобразовать его в несколько последовательных операций O(n). Чтобы выиграть time вы должны избавиться от space, поэтому, возможно, если вы создадите некоторую lookup table на основе данных в одном из ваших Enumerables, это поможет вам в этом случае.

Например, вы можете построить массив int который будет иметь значение, установленное для каждого дня, относящегося к периоду (каждый период имеет другое известное твердое значение). Это будет ваш первый цикл O (n). Затем вы делаете еще один цикл O (m) и проверяете, не находится ли положение массива, соответствующее row.Date ноль (тогда вы просматриваете фактическое значение среди жестко запрограммированных, и вы получаете фактический Period).

Во всяком случае, это более общая идея, и реализация важна. Если n и m очень малы, вы можете не принести никакой пользы, но если они большие (огромные), я могу поспорить, что метод Split будет работать быстрее.

Предполагая, что все, с чем вы работаете, уже находится в памяти (нет участия EF).

  • 0
    Было бы неплохо прокомментировать, когда вы проголосуете.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню