Подтвердить что ты не робот

LINQ Max() с нулями

У меня есть список, содержащий пучок точек (с компонентом X и Y).

Я хочу получить Max X для всех точек в списке, например:

double max = pointList.Max(p=> p.X);

Проблема заключается в том, что у меня есть нуль в списке вместо точки. Каким будет лучший способ обойти эту проблему?

4b9b3361

Ответ 1

Ну, вы можете просто отфильтровать их:

pointList.Where(p => p != null).Max(p => p.X)

С другой стороны, если вы хотите, чтобы null обрабатывался так, как если бы они были точками, имеющими X-координату 0 (или аналогичные), вы могли бы сделать:

pointList.Max(p => p == null ? 0 : p.X)

Обратите внимание, что оба метода будут метаться, если последовательность пуста. Одним из способов решения этой проблемы (если желательно) было бы следующее:

pointList.DefaultIfEmpty().Max(p => p == null ? 0 : p.X)

Ответ 2

Если вы хотите указать значение по умолчанию для X нулевой точки:

pointList.Max(p => p == null ? 0 : p.X)

Или предоставить значение по умолчанию для пустого списка:

int max = points.Where(p => p != null)
                .Select(p => p.X)
                .DefaultIfEmpty()
                .Max();

Ответ 3

Я бы не рекомендовал использовать DefaultIfEmpty в этом случае, так как он создает довольно большой SQL по сравнению с другими альтернативами.

Пожалуйста, посмотрите на этот пример:

У нас есть список модулей для страницы и мы хотим получить максимальное значение столбца "Сортировка". Если в списке нет записей, возвращается null. DefaultIfEmpty проверяет значение null и возвращает значение по умолчанию для типа данных столбца, когда столбец имеет значение null.

var max = db.PageModules.Where(t => t.PageId == id).Select(t => t.Sort).DefaultIfEmpty().Max();

В результате создается следующий SQL:

exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Join1].[A1]) AS [A1]
    FROM ( SELECT 
        CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Sort] END AS [A1]
        FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
        LEFT OUTER JOIN  (SELECT 
            [Extent1].[Sort] AS [Sort], 
            cast(1 as tinyint) AS [C1]
            FROM [dbo].[PageModules] AS [Extent1]
            WHERE [Extent1].[PageId] = @p__linq__0 ) AS [Project1] ON 1 = 1
    )  AS [Join1]
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go

Если вместо этого вместо столбца укажем значение nullable и пусть Convert.ToInt32() обрабатывает значение null так:

var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Max(t => (int?)t.Sort));

Затем мы получаем следующий SQL:

exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Extent1].[Sort]) AS [A1]
    FROM [dbo].[PageModules] AS [Extent1]
    WHERE [Extent1].[PageId] = @p__linq__0
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go

Я действительно рекомендую использовать ExpressProfiler для проверки SQL, который выполняется: http://expressprofiler.codeplex.com/

Последнее выражение Linq также может быть записано как:

var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Select(t => (int?)t.Sort).Max());

и будет выдавать тот же SQL, но мне нравится более краткий .Max(t => (int?)t.Sort).

Ответ 4

double max = pointList.Where(p=>p != null).Max(p=>p.X)

Должен работать.

Ответ 5

Попробуйте выполнить кастинг с нулевым значением

double max = (double?)pointList.Max(p => p.X);

больше: Макс. или по умолчанию?

Ответ 6

Почему бы просто:

double? maxOrNull  = pointList.
    .Where(p => p != null)
        .OrderByDescending(p => p.x)
        .FirstOrDefault();
double max = 0;
if (maxOrNull.HasValue) max = maxOrNull.Value;

Это будет работать в списках памяти и Linq2Sql и, вероятно, также эффективно.

Ответ 7

Поместите элемент с нулевым значением в INSIDE, чтобы убедиться, что пустым списком будет присвоено значение null. Затем вы можете добавить значения по умолчанию.

double max = pointList.Max(p=>(double?)p.X) ?? 0;