Linq:ForEach项目返回从该项

时间:2018-06-06 15:09:27

标签: c# linq

假设我有一个项目清单:

[a,b,b,a,c,d,a,d,b,c]

并且我需要知道,对于每个项目,我必须遍历多少项目,直到我获得n个唯一项目,(并返回例如-1,或以其他方式指示是否不可能)

所以在这里,如果n = 4,我会返回

[6,5,4,6,5,5,4,-1,-1,-1]

a,b,b,a,c,d包含4个独特元素

b,b,a,c,d包含4个独特元素

b,a,c,d包含4个唯一元素

a,c,d,a,d,b包含4个独特元素

2 个答案:

答案 0 :(得分:0)

我用过

List.Select((x,i) => {
    var range = List.Skip(i).GroupBy(y => y).Take(n);
    if (range.Count() == n)
        return range.SelectMany(y => y).Count();
    return -1;
});

虽然我非常确定这是非常不具备性能的。

答案 1 :(得分:0)

为了尽量减少开销,我创建了一个ListSpan扩展类来管理List的子部分 - 类似于ArraySegment的{​​{1}},但是(松散地)建模List

Span

然后我创建了一个扩展方法来返回从public class ListSpan<T> : IEnumerable<T>, IEnumerable { List<T> baseList; int start; int len; public ListSpan(List<T> src, int start = 0, int? len = null) { baseList = src; this.start = start; this.len = len ?? (baseList.Count - start); if (this.start + this.len > baseList.Count) throw new ArgumentException("start+len > Count for ListSpan"); } public T this[int n] { get { return baseList[start + n]; } set { baseList[start + n] = value; } } public class ListSpanEnumerator<Te> : IEnumerator<Te>, IEnumerator { int pos; List<Te> baseList; int end; Te cur = default(Te); public ListSpanEnumerator(ListSpan<Te> src) { pos = src.start - 1; baseList = src.baseList; end = src.start + src.len; } public Te Current => cur; object IEnumerator.Current => Current; public bool MoveNext() { if (++pos < end) { cur = baseList[pos]; return true; } else { cur = default(Te); return false; } } public void Reset() => pos = 0; public void Dispose() { } } public IEnumerator<T> GetEnumerator() => new ListSpanEnumerator<T>(this); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } public static class ListExt { public static ListSpan<T> Slice<T>(this List<T> src, int start = 0, int? len = null) => new ListSpan<T>(src, start, len); } 获取n个唯一项所需的距离(Take个术语):

IEnumerable

现在答案相对简单:

public static class IEnumerableExt {
    public static int DistanceToUnique<T>(this IEnumerable<T> src, int n, IEqualityComparer<T> cmp = null) {
        var hs = new HashSet<T>(cmp ?? EqualityComparer<T>.Default);
        var pos = 0;
        using (var e = src.GetEnumerator()) {
            while (e.MoveNext()) {
                ++pos;
                hs.Add(e.Current);
                if (hs.Count == n)
                    return pos;
            }
        }
        return -1;
    }
}

基本上,我会检查原始(var ans = Enumerable.Range(0, src.Count).Select(p => src.Slice(p).DistanceToUnique(n)); src中的每个位置,并使用List的{​​{1}}来计算距该位置的n个唯一值的距离在那个位置。

这仍然不是非常有效,因为我正在为原始ListSpan中的每个元素创建List并将所有以下元素放入其中,并将元素遍历到k ! k元素HashSet的时间。仍然试图想出一些非常有效的东西。