我有一個資料集(例如 1、1、4、6、3、3、1、2、2、2、6、6、6、7),我想對具有相同值的專案進行分組,但前提是它們彼此相鄰至少 3 次。
有辦法嗎?我已經嘗試過以我知道的所有方式使用 Count 和 GroupBy 和 Select 的組合,但我找不到合適的組合。
或者,如果它不能用 LINQ 完成,那么也許有其他方式?
uj5u.com熱心網友回復:
我不認為我會為此爭取 100% 的 LINQ 解決方案:
var r = new List<List<int>>() { new () { source.First() } };
foreach(var e in source.Skip(1)){
if(e == r.Last().Last()) r.Last().Add(e);
else r.Add(new(){ e });
}
return r.Where(l => l.Count > 2);
如果您愿意,可以將.Last()呼叫替換為[^1]
輸出如:
[
[2,2,2],
[6,6,6]
]
可以推動聚合做同樣的事情;這只是一個累加器 ( r)、一個迭代 ( foreach) 和一個對結果的操作Where
var result = source.Skip(1).Aggregate(
new List<List<int>>() { new List<int> { source.First() } },
(r,e) => {
if(e == r.Last().Last()) r.Last().Add(e);
else r.Add(new List<int>(){ e });
return r;
},
r => r.Where(l => l.Count > 2)
);
..但是你想成為向新開發者解釋它的人嗎?
另一種 LINQy 方法是建立一個計數器,每次源陣列中的值與以前的版本相比發生變化時,該計數器增加一,然后按此整數分組,并僅回傳那些組 3 ,但我不喜歡這樣很大程度上是因為它有點“WTF”
var source = new[]{1, 1, 4, 6, 3, 3, 1, 2, 2, 2, 6, 6, 6, 7};
int ctr = 0;
var result = source.Select(
(e,i) => new[]{ i==0 || e != source[i-1] ? ctr : ctr, e}
)
.GroupBy(
arr => arr[0],
arr => arr[1]
)
.Where(g => g.Count() > 2);
uj5u.com熱心網友回復:
如果你很懷舊并且喜歡混淆 C 代碼競賽之類的東西,你可以像這樣解決它。
(不包括最佳實踐宣告)
int[] n = {1, 1, 4, 6, 3, 3, 1, 2, 2, 2, 6, 6, 6, 7};
var t = new int [n.Length][];
for (var i = 0; i < n.Length; i )
t[i] = new []{n[i], i == 0 ? 0 : n[i] == n[i - 1] ? t[i - 1][1] : t[i - 1][1] 1};
var r = t.GroupBy(x => x[1], x => x[0])
.Where(g => g.Count() > 2)
.SelectMany(g => g);
Console.WriteLine(string.Join(", ", r));
最后,Linq 可能不是這里最好的解決方案。帶有 1,2,3 個附加回圈變數的簡單 for 回圈來跟蹤“組索引”和最后一個值可能更有意義。即使多寫兩行代碼。
uj5u.com熱心網友回復:
我不會僅僅為了使用 Linq 而使用 Linq。
我寧愿建議使用簡單的 for 回圈來遍歷您的input陣列并填充output串列。為了跟蹤當前正在重復的數字(如果有的話),我會使用一個repeatedNumber最初設定為null.
repeatedNumber在這種方法中,只有滿足重復項的最低要求才能分配一個編號。因此,對于您的示例輸入,repeatedNumber將從 開始null,然后最終設定為2,然后設定為6,然后重置為null。
此處 Linq 的一個可能很好的用途是通過檢查 in 中的必要連續項來檢查給定項 in 是否滿足重復項的最低要求:inputinput
input
.Skip(items up to and including current item)
.Take(minimum requirement of repeated items - 1)
.All(equal to current item)
我將把這個重復項的最低要求命名為 repetitionRequirement。(在您的問題帖子中,repetitionRequirement是3。)
for 回圈中的邏輯如下:
number = input[i]- 如果
number等于repeatedNumber,則表示之前重復的專案繼續被重復- 添加
number到output
- 添加
- 否則,如果滿足重復項的最小要求
number(即如果repetitionRequirement - 1緊跟number在的項input都等于number),則表示它number是新的重復項的第一個實體- 設定
repeatedNumber等于number - 添加
number到output
- 設定
- 否則,如果
repeatedNumber有 value,則表示之前重復的專案剛剛結束了它的重復- 設定
repeatedNumber為null
- 設定
這是一個建議的實作:(
我建議找到一個更具描述性的方法名稱)
//using System.Collections.Generic;
//using System.Linq;
public static List<int> GetOutput(int[] input, int repetitionRequirement)
{
var consecutiveCount = repetitionRequirement - 1;
var output = new List<int>();
int? repeatedNumber = null;
for (var i = 0; i < input.Length; i )
{
var number = input[i];
if (number == repeatedNumber)
{
output.Add(number);
}
else if (i consecutiveCount < input.Length &&
input.Skip(i 1).Take(consecutiveCount).All(num => num == number))
{
repeatedNumber = number;
output.Add(number);
}
else if (repeatedNumber.HasValue)
{
repeatedNumber = null;
}
}
return output;
}
通過使用您的示例輸入呼叫它:
var dataSet = new[] { 1, 1, 4, 6, 3, 3, 1, 2, 2, 2, 6, 6, 6, 7 };
var output = GetOutput(dataSet, 3);
你得到以下輸出:
{ 2, 2, 2, 6, 6, 6 }
示例小提琴在這里。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/473352.html
上一篇:.NETCore應用程式和System.Reflection.Assembly.LoadFrom(...)是否存在特定問題?
