我目前正在開發一個 .NET Core 應用程式。
我需要按以下要求過濾 LINQ 查詢:
- Id:如果沒有ContactId,只選一次Id (1)
- Id 和 ContactId:如果存在過濾器 Id (1) 并添加 Id 和 Contact Id 對 (1, 1)
- Id 和 ContactId 對必須是唯一的,但可以不同,例如:(1, 1), (1, 5)
- 必須洗掉空物件
public class SearchResult
{
public int? Id {get; set;}
public int? ContactId {get; set;}
}
public class Program
{
public static void Main()
{
var searchResults = new List<SearchResult>
{
new SearchResult { Id = 1 },
new SearchResult { },
new SearchResult { Id = 2 }, // yes
new SearchResult { Id = 3 }, // yes
new SearchResult { Id = 4 }, // yes
new SearchResult { Id = 5 },
new SearchResult { Id = 5, ContactId = 3 }, // yes
new SearchResult { Id = 1, ContactId = 1 }, // yes
new SearchResult { Id = 1, ContactId = 5 }, // yes
new SearchResult { Id = 8, ContactId = 4 }, // yes
new SearchResult { Id = 1 },
new SearchResult { Id = 2 },
new SearchResult { Id = 10 }, // yes
new SearchResult { Id = 11 }, // yes
new SearchResult { Id = 12 }, // yes
};
// unfortunately this LINQ query does not work correctly:
var result = searchResults
.OrderBy(x => x.Id)
.ThenBy(x => x.ContactId)
.GroupBy(p => new { p.Id, p.ContactId })
.Select(x => x.First());
foreach(var sr in result){
Console.WriteLine(sr.Id " " sr.ContactId);
}
}
預期的結果應該是:
1 1
1 5
2
3
4
5 3
8 4
10
11
12
不幸的是,我的 LINQ 查詢無法正常作業。
你知道如何解決這個問題并根據規則過濾 LINQ 查詢嗎?
uj5u.com熱心網友回復:
我建議這樣的事情。下面我們GroupBy再分別分析每一組。最后,我們將s壓 group回到IEnumerable<SearchResult>(please, fiddle )
為了洗掉重復項,我們應該知道如何比較專案是否相等,然后呼叫Distinct. 我們可以為此實作 IEqualityComparer:
private class MyEqualityComparer : IEqualityComparer<SearchResult> {
public bool Equals(SearchResult x, SearchResult y) {
if (ReferenceEquals(x, y))
return true;
else if (null == x || null == y)
return false;
return x.Id == y.Id && x.ContactId == y.ContactId;
}
public int GetHashCode(SearchResult obj) => (obj != null && obj.Id.HasValue)
? obj.Id.Value
: 0;
}
最終代碼:
var result = searchResults
.Where(item => item.ContactId.HasValue || item.Id.HasValue)
.Distinct(new MyEqualityComparer()) // remove duplicates
.GroupBy(item => item.Id)
.Select(group => group.Any(item => item.ContactId.HasValue)
? group.Where(item => item.ContactId.HasValue)
: group.Take(1))
.SelectMany(group => group);
我們來看一下:
Console.WriteLine(string.Join(Environment.NewLine, result
.Select(item => $"{item.Id} {item.ContactId}")));
結果:
1 1
1 5
2
3
4
5 3
8 4
10
11
12
uj5u.com熱心網友回復:
Dmitry Bychenko 的解決方案很好,除了一個錯誤:
它不會洗掉重復的對。
編輯這不再是這種情況,錯誤已得到糾正。
這似乎是強制性的:
Id 和 ContactId 對必須是唯一的,但可以不同,例如:(1, 1), (1, 5)
為此,您可以使用Distinct運算子,但由于 SearchResult 是一個類,Distinct因此不會比較每個實體的值,而是比較其參考。所以我只是將每個 SearchResult 投影到一個值元組,以便快速比較值而不是參考。
var result = searchResults
.Where(e => e.ContactId.HasValue || e.Id.HasValue)
.Select(e => (Id: e.Id, ContactId: e.ContactId))
.GroupBy(e => e.Id)
.Select(g => g.Any(e => e.ContactId.HasValue)
? g.Where(e => e.ContactId.HasValue).Distinct()
: g.Take(1))
.SelectMany(g => g)
.Select(e => new SearchResult
{
Id = e .Id,
ContactId = e.ContactId
});
此外,您沒有指定 SearchResult 具有 ContactId 而沒有 Id 的情況。當前代碼的行為它接受這樣的一對。
如果要過濾這些,只需更改此行
.Where(e => e.ContactId.HasValue || e.Id.HasValue)
經過
.Where(e => e.Id.HasValue)
下面是一個完整的 Linqpad 查詢供您嘗試。我添加了重復項和 SearchResults 的空 ID 和非空 ContactId
public static void Main()
{
var searchResults = new List<SearchResult>
{
new SearchResult { Id = 1 },
new SearchResult { },
new SearchResult { ContactId = 45}, // IS accepted, but the behavior was not specified.
new SearchResult { ContactId = 45},
new SearchResult { ContactId = 42},
new SearchResult { ContactId = 45},
new SearchResult { ContactId = 45},
new SearchResult { Id = 2 }, // yes
new SearchResult { Id = 3 }, // yes
new SearchResult { Id = 4 }, // yes
new SearchResult { Id = 5 },
new SearchResult { Id = 5 },
new SearchResult { Id = 5 },
new SearchResult { Id = 5 },
new SearchResult { Id = 5, ContactId = 3 }, // yes
new SearchResult { Id = 1, ContactId = 1 }, // yes
new SearchResult { Id = 1, ContactId = 5 }, // yes
new SearchResult { Id = 8, ContactId = 4 }, // yes
new SearchResult { Id = 8, ContactId = 4 },
new SearchResult { Id = 8, ContactId = 4 },
new SearchResult { Id = 8, ContactId = 4 },
new SearchResult { Id = 1 },
new SearchResult { Id = 2 },
new SearchResult { Id = 10 }, // yes
new SearchResult { Id = 11 }, // yes
new SearchResult { Id = 12 }, // yes
};
var result = searchResults
.Where(e => e.ContactId.HasValue || e.Id.HasValue)
.Select(e => (Id: e.Id, ContactId: e.ContactId))
.GroupBy(e => e.Id)
.Select(g => g.Any(e => e.ContactId.HasValue)
? g.Where(e => e.ContactId.HasValue).Distinct()
: g.Take(1))
.SelectMany(g => g)
.Select(e => new SearchResult
{
Id = e .Id,
ContactId = e.ContactId
})
.Dump();
}
public class SearchResult
{
public int? Id { get; set; }
public int? ContactId { get; set; }
}
編輯 根據提問者的要求:
可以擺脫元組投影,但仍然可以從該Distinct方法中受益。
One solution is to have the SearchResult class implement the IEquatable Interface:
public class SearchResult : IEquatable<SearchResult>
{
public int? Id { get; set; }
public int? ContactId { get; set; }
public bool Equals(SearchResult other)
{
return Id == other.Id && ContactId == other.ContactId;
}
public override int GetHashCode()
{
int hashId = Id == null ? 0 : Id.GetHashCode();
int hashContactId = ContactId == null ? 0 : ContactId.GetHashCode();
return hashId ^ hashContactId;
}
}
The query is then simplified into:
var result = searchResults
.Where(e => e.ContactId.HasValue || e.Id.HasValue)
.GroupBy(e => e.Id)
.Select(g => g.Any(e => e.ContactId.HasValue)
? g.Where(e => e.ContactId.HasValue).Distinct()
: g.Take(1))
.SelectMany(g => g);
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/360045.html
下一篇:在某些位置有字母的單詞串列中查找
