是否有等同于 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 option
或 Maybe<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 字符串分组。
我进行的每次搜索都假设 "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 option
或 Maybe<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 字符串分组。