将自定义选择器委托传递给LINQ的GroupBy?

时间:2014-04-05 17:01:38

标签: c# linq group-by

所以我有这个扩展,在KeyValuePair中返回IEnumerable重复项(键)及其对应的索引(值)。

    public static IEnumerable<KeyValuePair<TSource, int[]>> GetDuplicates<TSource>(this IEnumerable<TSource> e)
    {
        return e.Select((value, index) => new { Index = index, Value = value })
                .GroupBy(x => x.Value)
                .Select(xg => new KeyValuePair<TSource, int[]>(xg.Key, xg.Select(x => x.Index).ToArray()))
                .Where(kv => kv.Value.Length > 1);
    }

我试图做一个非常基本的事情 - 我想注入一个自定义选择器,以便我可以进入GroupBy - 我试过这个:

    public static IEnumerable<KeyValuePair<TSource, int[]>> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> e, Func<TSource, TKey> selector)
    {
        return e.Select((value, index) => new { Index = index, Value = value })
                .GroupBy(x => selector(x.Value))
                .Select(xg => new KeyValuePair<TSource, int[]>(xg.Key, xg.Select(x => x.Index).ToArray()))
                .Where(kv => kv.Value.Length > 1);
    }

但是我在KeyValuePair

的新功能中出现了无效的参数错误

似乎我对应该传递的所有通用参数感到困惑 - 我不确定如何将它们连接起来:s

我认为这里的问题是选择器应该返回第一个Select投影的匿名类型 - 而不是TKey - 但是如何注入匿名类型泛型arg?

有什么想法吗?

感谢。

编辑:

找到了一个解决方法 - 不是很好,但它可以工作并显示我想要的东西。

    private static List<TSource> GetDups<TSource, TKey>(List<TSource> source, Func<TSource, TKey> selector)
    {
        var dupGosIndices = source
            .Select(selector)
            .GetDuplicates().Select(x => x.Value);

        var dupGos = new List<TSource>();
        foreach (IEnumerable<int> indicesList in dupGosIndices) {
            dupGos.Add(source[indicesList.ElementAt(0)]);
        }
        return dupGos;
    }

1 个答案:

答案 0 :(得分:1)

试试这个? IGrouping<Key, IEnumerable<TSource>>上的分组将具有相同的TSource值,因此请继续抓取第一个。

            return e.Select((value, index) => new { Index = index, Value = value })
                .GroupBy(x => selector(x.Value))
                .Select(xg => new KeyValuePair<TSource, int[]>(xg.Select(x => x.Value).First(), xg.Select(x => x.Index).ToArray()))
                .Where(kv => kv.Value.Length > 1);