是否有等同于 unix 命令 uniq 的 Linq

Is there a Linq equivalent to the unix command uniq

我进行的每次搜索都假设 "Distinct()",但这不是我的要求。我只想删除所有重复项。是否有任何使用 linq 的选项(即可枚举扩展)?

例如(在 C# 中)

int[] input = new [] {1,2,3,3,4,5,5,5,6,6,5,4,4,3,2,1,6};

int[] expected = new [] {1,2,3,4,5,6,5,4,3,2,1,6};

使用 linq 是可能的,尽管为了性能和可读性,简单的 for 循环可能是更好的选择。

int[] input = new[] { 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 5, 4, 4, 3, 2, 1, 6 };
var result = input.Where((x, i) => i == 0 || x != input[i - 1]).ToArray();

您要求 non-repeating 个元素,而不是唯一元素。 LINQ-to-Objects 操作本质上是迭代器。您可以编写自己的迭代器方法,仅在第一次遇到项目时产生,例如:

public static IEnumerable<int> DistinctUntilChanged(this IEnumerable<int> source)
{
    int? previous=null;
    foreach(var item in source)
    {
        if (item!=previous)
        {
            previous=item;
            yield return item;
        }
    }
}

var input = new [] {1,2,3,3,4,5,5,5,6,6,5,4,4,3,2,1,6};
var result=input.DistinctUntilChanged().ToArray();

结果将是:

{1,2,3,4,5,6,5,4,3,2,1,6};

更新

另一种选择是使用 System.Reactive 库中的 Observable.DistinctUntilChanged,例如:

var input = new[] { 1, 2, 3, 3, 4, 5, 5, 5, 6, 6, 5, 4, 4, 3, 2, 1, 6 };
var result = input.ToObservable()
                  .DistinctUntilChanged()
                  .ToEnumerable()
                  .ToArray();

System.Reactive 和 Reactive Extensions 旨在使用基本的 LINQ 运算符等处理事件序列。不过,使用 ToObservable()ToEnumerable() 可以很容易地在 Observable 和 Enumerable 之间进行转换,因此它们可用于处理任何集合。毕竟,事件序列类似于 "infinite" 序列

更新 2

如果对使用 int? 存储前一个数字有任何混淆,即使与源的 first 元素也可以轻松比较,实际上没有在上面调用 First()。如果是,例如 int previous=0; 并且第一个元素是 0,则比较将过滤掉第一个元素。

通过在 C# 中使用 int? 或在 F# 中使用 int optionMaybe<int> 如果我们有一个 Maybe monad,我们可以区分没有初始值和初始值为 0 .

Observable.DistinctUntilChanged 使用标志来检查我们是否正在检查第一个元素。等效代码为:

    public static IEnumerable<int> NonRepeating(this IEnumerable<int> source)
    {
        int previous =0;
        bool isAssigned=false;
        foreach (var item in source)
        {
            if (!isAssigned || item != previous)
            {
                isAssigned = true;
                previous = item;
                yield return item;
            }
        }
    }

MoreLINQ

最后,可以使用 MoreLinq 库中的 GroupAdjacent 方法将重复项组合在一起。每个组都包含重复的源元素。在这种特殊情况下,尽管我们只需要键值:

var result = input.GroupAdjacent(i => i).Select(i => i.Key).ToArray();

GroupAdjacent 的好处是元素可以在分组时进行转换,例如:

input.GroupAdjacent(i => i,i=>$"Number {i}")

将 return 字符串分组。