Тождественное отображение LINQ?

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

39
задан Joe 23 September 2009 в 15:20
поделиться

3 ответа

Примечание: этот ответ был правильным для C # 3, но в какой-то момент (C # 4? C # 5?) Вывод типа улучшился, так что метод IdentityFunction , показанный ниже ] можно легко использовать


Нет, нет. Он должен быть общим, для начала:

public static Func<T, T> IdentityFunction<T>()
{
    return x => x;
}

Но тогда вывод типа не будет работать, поэтому вам придется сделать:

SelectMany(Helpers.IdentityFunction<Foo>())

, что намного уродливее, чем x => x .

Другая возможность состоит в том, что вы оберните это в метод расширения:

public static IEnumerable<T> Flatten<T>
    (this IEnumerable<IEnumerable<T>> source)
{
    return source.SelectMany(x => x);
}

К сожалению, с такой общей дисперсией, которая может не подходить для различных случаев в C # 3 ... это не будет применимо к Например, список > . Вы могли бы сделать его более общим:

public static IEnumerable<TElement> Flatten<TElement, TWrapper>
    (this IEnumerable<TWrapper> source) where TWrapper : IEnumerable<TElement>
{
    return source.SelectMany(x => x);
}

Но опять же, у вас возникли проблемы с выводом типов, я подозреваю ...

EDIT: Чтобы ответить на комментарии ... да, C # 4 упрощает эту задачу. Или, скорее, это делает первый метод Flatten более полезным, чем в C # 3. Вот пример, который работает в C # 4, но не работает в C # 3, потому что компилятор не может преобразовать из List > до IEnumerable > :

using System;
using System.Collections.Generic;
using System.Linq;

public static class Extensions
{
    public static IEnumerable<T> Flatten<T>
        (this IEnumerable<IEnumerable<T>> source)
    {
        return source.SelectMany(x => x);
    }
}

class Test
{
    static void Main()
    {
        List<List<string>> strings = new List<List<string>>
        {
            new List<string> { "x", "y", "z" },
            new List<string> { "0", "1", "2" }
        };

        foreach (string x in strings.Flatten())
        {
            Console.WriteLine(x);
        }
    }
}
30
ответ дан 27 November 2019 в 02:29
поделиться

Does this work in the way you want? I realize Jon posted a version of this solution, but he has a second type parameter which is only necessary if the resulting sequence type is different from the source sequence type.

public static IEnumerable<T> Flatten<T>(this IEnumerable<T> source)
    where T : IEnumerable<T>
{
    return source.SelectMany(item => item);
}
3
ответ дан 27 November 2019 в 02:29
поделиться

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

public static Func<T, T> IdentityFunction<T>(this IEnumerable<T> enumerable)
{
     return x => x;
}

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

IEnumerable<IEnumerable<T>> deepList = ... ;
var flat = deepList.SelectMany(deepList.IdentityFunction());

Это действительно немного оскорбительно, и я, вероятно, выбрал бы x => x . Кроме того, вы не можете использовать его плавно (в цепочке), поэтому он не всегда будет полезен.

2
ответ дан 27 November 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: