C# linq 從串列的頂部和底部洗掉重復項并將重復項保留在中間
例如,
var myArray = new[] {
1, 1, 2, 2, 3, 4, 5, 5, 9, 9
};
List<int> myList = myArray.ToList();
洗掉頂部和底部的重復項后的預期輸出如下串列
{ 2, 2, 3, 4, 5, 5 };
請建議如何執行此邏輯并嘗試myList.Distinct()無濟于事,因為它也會洗掉中間的所有重復項。
**編輯:串列不會為空,無論頂部和底部是否重復,都應洗掉第一條和最后一條記錄以計算業務邏輯。如果在頂部或底部發現重復項,也應洗掉。該串列將在執行洗掉操作之前按升序排列**
uj5u.com熱心網友回復:
如果您只想從集合的頂部和底部洗掉重復項,但希望在中間保持相同的值:
1, 1, 2, 3, 1, 1, 8, 8, 9, 9, 4, 5, 9, 9 => 2, 3, 1, 1, 8, 8, 9, 9, 4, 5
^ ^ ^ ^
preserved
您可以計算left和right邊界,然后借助 and 修剪Skip集合Take:
int[] myArray = new int[] {
...
};
...
int left = 0;
for (int i = 1; i < myArray.Length; i)
if (myArray[i - 1] == myArray[i])
left = i 1;
else
break;
int right = myArray.Length - 1;
for (int i = myArray.Length - 2; i >= 0; --i)
if (myArray[i 1] == myArray[i])
right = i - 1;
else
break;
List<int> myList = myArray
.Skip(left)
.Take(right - left 1)
.ToList();
如果要洗掉所有看起來重復的值
1, 1, 2, 3, 1, 1, 8, 8, 9, 9, 4, 5, 9, 9 => 2, 3, 8, 8, 4, 5
您可以收集這些值,然后過濾掉:
int[] myArray = new int[] {
...
};
...
HashSet<int> remove = new HashSet<int>();
if (myArray.Length > 1) {
if (myArray[0] == myArray[1])
remove.Add(myArray[0]);
if (myArray[myArray.Length - 1] == myArray[myArray.Length - 2])
remove.Add(myArray[myArray.Length - 1]);
}
var myList = myArray
.Where(item => !remove.Contains(item))
.ToList();
請拉小提琴
uj5u.com熱心網友回復:
要洗掉串列開頭的重復項,您可以從System.Linq命名.First()空間中受益:.SkipWhile()
var firstDuplicate = myList.First();
var listWithoutFirstDuplicate = myList
.SkipWhile(l => l == firstDuplicate)
.ToList();
要洗掉串列末尾的重復項,您將受益于.Last()and .SkipLastWhile(), had .SkipLastWhile()exists:
var lastDuplicate = myList.Last();
var listWithoutLastDuplicate = myList
.SkipLastWhile(l => l == lastDuplicate)
.ToList();
.SkipLastWhile()Paulo Morgado在這篇博文中建議了一個實作。它看起來像這樣:
public static IEnumerable<TSource> SkipLastWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
var buffer = new List<TSource>();
foreach (var item in source)
{
if (predicate(item))
{
buffer.Add(item);
}
else
{
if (buffer.Count > 0)
{
foreach (var bufferedItem in buffer)
{
yield return bufferedItem;
}
buffer.Clear();
}
yield return item;
}
}
}
Paulo 的實作會.SkipLastWhile()根據謂詞檢查每個元素。如果某個元素的謂詞不滿足,則回傳該元素。如果滿足謂詞(即在您的場景中:如果元素等于lastDuplicate),則不會立即回傳該元素,而是將其添加到緩沖區中。僅當后續元素不滿足謂詞時才回傳緩沖區的內容。
幾個例子:
{ 1, 9, 9, 9, 9 }.SkipLastWhile(i => i == 9)
將回傳{ 1 }。
緩沖區將從{ 9 }(索引 1 處的元素)建立到{ 9, 9, 9, 9 }(索引 1 到索引 4 的元素),并且不會被回傳。
{ 1, 9, 9, 9, 9, 1 }.SkipLastWhile(i => i == 1)
將回傳{ 1, 9, 9, 9, 9 }。
緩沖區將首先是{ 1 }(索引 0 處的元素),然后在9找到時回傳并清空(索引 1 處)。當到達最后一個元素時,緩沖區將再次為{ 1 }; 它不會被退回。
{ 9, 1, 9, 9, 9, 9 }.SkipLastWhile(i => i == 9)
將回傳{ 9, 1 }。
緩沖區將首先是{ 9 }(索引 0 處的元素),然后在1找到時回傳并清空(索引 1 處)。當到達9(在索引 2 處)時,緩沖區開始再次建立,從{ 9 }. 在最后一個元素處,緩沖區將為{ 9, 9, 9, 9 },并且不回傳其內容。
使用 的這個實作SkipLastWhile(),您可以獲得過濾后的串列:
var myList = new List<int> { 1, 1, 9, 2, 2, 3, 9, 4, 5, 5, 1, 9, 9 };
var firstDuplicate = myList.First();
var lastDuplicate = myList.Last();
var myFilteredList = myList
.SkipWhile(l => l == firstDuplicate)
.SkipLastWhile(l => l == lastDuplicate)
.ToList();
給定的輸出myList如下:
9, 2, 2, 3, 9, 4, 5, 5, 1
正如Dmitry Bychenko所指出的,這種實作存在兩個問題:
- if
myListisnullor empty({ }),拋出例外- 沒有一個擴展方法可以容忍被呼叫
null .First()(和.Last())在空串列上呼叫時拋出例外
- 沒有一個擴展方法可以容忍被呼叫
- 如果第一個元素不重復(即不等于第二個元素),則仍然會排除第一個元素;這不是預期的行為。同樣,最后一個元素也將被排除,即使它沒有重復。
解決這些問題的一種方法是在過濾掉實際重復項之前進行檢查。如果在方法中處理,可以這樣實作:
public static List<int> GetFilteredList(List<int> list)
{
// if list is null; return null
if (list == null)
{
return null;
}
// If list is empty or contains only one element; return list as new list
if (!list.Skip(1).Any())
{
return list.ToList();
}
var filtered = list.AsEnumerable();
// Remove duplicates at beginning of list (if any)
if (list.First() == list.Skip(1).First())
{
filtered = filtered.SkipWhile(l => l == list.First());
}
// Remove duplicates at end of list (if any)
if (list.Last() == list.SkipLast(1).Last())
{
filtered = filtered.SkipLastWhile(l => l == list.Last());
}
return filtered.ToList();
}
可以這樣呼叫:
var filteredList = GetFilteredList(myList);
示例小提琴在這里。
uj5u.com熱心網友回復:
var myList = new List<int> { 1, 1, 2, 2, 3, 4, 5, 5, 9, 9 };
var topDublicate = myList.First();
var lastDublicate = myList.Last();
myList.RemoveAll(l => l == topDublicate);
myList.RemoveAll(l => l == lastDublicate);
uj5u.com熱心網友回復:
int topDuplicate = myList [0];
myList .RemoveAll(x => x == topDuplicate);
int bottomDuplicate = myList [myList .Count - 1];
myList .RemoveAll(x => x == bottomDuplicate);
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/476606.html
