2016-11-24 60 views
5

我正在使用充滿項目之間相似性的矩陣。我將它們保存爲數據庫中的對象列表。 Similarity對象如下所示:LINQ中的條件GroupBy()

public class Similarity 
{ 
    public virtual Guid MatrixId { get; set; } //The id of the matrix the similarity is in 
    public virtual Guid FirstIndex { get; set; } //The id of the item of the left side of the matrix 
    public virtual Guid SecondIndex { get; set; } //The id of the item of the top side of the matrix 
    public virtual double Similarity { get; set; } //The similarity 
} 

用戶可以查看這些項目。我想要檢索與用戶已審閱的項目「相似」的項目列表。問題是我無法確定物品的ID是在FirstIndex還是SecondIndex。我寫了一些代碼,它可以做我想做的,但是我想知道這是否可能在1語句中。

var itemsNotReviewed = Similarities.Where(x => !itemsReviewed.Contains(x.SecondIndex)) 
    .GroupBy(x => x.SecondIndex) 
    .ToList(); 
itemsNotReviewed.AddRange(Similarities.Where(x => !itemsReviewed.Contains(x.FirstIndex)) 
    .GroupBy(x => x.FirstIndex) 
    .ToList()); 

哪裏itemsReviewed是項目的GUID的列表,用戶已審查並在那裏Similarities是類似於用戶已檢查的項目中所有物品的清單。我檢索列表使用此功能:

return (from Row in _context.SimilarityMatrix 
     where itemIds.Contains(Row.FirstIndex) || itemIds.Contains(Row.SecondIndex) 
     select Row) 
     .Distinct() 
     .ToList(); 

其中itemIds是用戶已經檢查的項目中的GUID的列表。

有沒有一種方法可以通過基於Where子句的第一個或第二個索引進行分組?

請讓我知道,如果我應該詳細說明!

+0

霍普(HTTP [在LINQ結合WHERE子句和GROUP BY]:// stackoverflow.com/a/802337/3796048)可能會幫助你 –

+0

@MohitShrivastava你如何確定哪個索引是分組的關鍵? – RandomStranger

回答

3

按照我的理解,你有一個Similarity這是保證包含FirstIndexSecondIndex包含在itemsReviewed名單Guid的項目清單。並且您需要將元素(如果有)與itemsReviewed中包含的索引而不是(由於第一個約束,它可能只是其中的一個)並按該索引進行分組。

的簡單LINQ翻譯上面會是這樣:

var itemsNotReviewed = Similarities 
    .Where(item => !itemsReviewed.Contains(item.FirstIndex) || !itemsReviewed.Contains(item.SecondIndex)) 
    .GroupBy(item => !itemsReviewed.Contains(item.FirstIndex) ? item.FirstIndex : item.SecondIndex) 
    .ToList(); 

但它包含重複itemsReviewed.Contains檢查,其負面影響的表現。

因此,一個更好的方法將被引入中間變量,要做到這一點是查詢語法和let條款最簡單的方法:

var itemsNotReviewed = 
    (from item in Similarities 
    let index = !itemsReviewed.Contains(item.FirstIndex) ? 1 : 
      !itemsReviewed.Contains(item.SecondIndex) ? 2 : 0 
    where index != 0 
    group item by index == 1 ? item.FirstIndex : item.SecondIndex) 
    .ToList(); 
+0

我很欣賞這個輸入,但是他給了我一個解決方案來防止問題而不是解決問題。我自己做了一些思考,並稍微修改了一下,這樣可以處理我的代碼。 – RandomStranger

+1

沒問題,如果是這樣 - 畢竟這是你的問題:)我的帖子是基於**我已經寫了一些代碼,在你的文章中做我想要的**語句。如果這是錯誤的,請更新問題,我將刪除答案。我確定我發佈的代碼與您的代碼完全一樣,但只需一步。 –

+1

我剛剛意識到你是對的,你根據我的帖子給了我正確的答案,所以你應該得到賞金。藉口! – RandomStranger

1

我會去改變你源原始列表的方式:

_context.SimilarityMatrix.Where(Row => itemIds.Contains(Row.FirstIndex) || itemIds.Contains(Row.SecondIndex)) 
    .Select(r => new { r.MatrixId, r.FirstIndex, r.SecondIndex, r.Similarity, MatchingIndex = itemIds.Contains(r.FirstIndex) ? r.FirstIndex : r.SecondIndex }) 
    .Distinct() 
    .ToList(); 

這樣,你只能通過匹配 - 需要組。

var itemsNotReviewed = Similarities. 
.GroupBy(x => x.MatchingIndex) 
.ToList(); 

您可能希望將動態對象轉換爲您的相似性類,或者只是將類更改爲包含匹配索引。

您可以將它們轉換成你的相似類型:

var itemsNotReviewed = Similarities. 
.GroupBy(x => x.MatchingIndex) 
.Select(g => new { g.Key, Values = g.Values.Select(d => new Similarity { MatrixId = d.MatrixId, FirstIndex = d.FirstIndex, SecondIndex = d.SecondIndex, Similarity = d.Similarity }).ToList() }) 
.ToList(); 
+0

所以'MatchingIndex'會是'itemIds'列表中的ID嗎? – RandomStranger

+0

準確地說,它會是ID在物品ID – Juan

+0

好吧,謝謝,但只是要記住,該函數將不得不返回一個「相似性」對象的列表,我將如何將這些匿名類型轉換爲對象? – RandomStranger

0

什麼

(from x in Similarities 
let b2 = !itemsReviewed.Contains(x.SecondIndex) 
let b1 = !itemsReviewed.Contains(x.FirstIndex) 
where b1 || b2 
groupby b2 ? x.SecondIndex : x.FirstIndex into grp 
select grp) 
.ToList() 

的let語句引入了一個新的變量tempoary存儲布爾值。你當然可以內聯的其他功能,也:

(from x in (from Row in _context.SimilarityMatrix 
      where itemIds.Contains(Row.FirstIndex) || itemIds.Contains(Row.SecondIndex) 
      select Row) 
      .Distinct() 
      .ToList() 
let b2 = !itemsReviewed.Contains(x.SecondIndex) 
let b1 = !itemsReviewed.Contains(x.FirstIndex) 
where b1 || b2 
groupby b2 ? x.SecondIndex : x.FirstIndex into group 
select group) 
.ToList() 

如果你想使用非LINQ的語法,你可能需要引入一些匿名類型:

Similarities 
.Select(s => new 
{ 
    b2 = !itemsReviewed.Contains(x.SecondIndex), 
    b1 = !itemsReviewed.Contains(x.FirstIndex), 
    s 
}) 
.Where(a => a.b1 || a.b2) 
.GroupBy(a => a.b2 ? a.s.SecondIndex : a.s.FirstIndex, a => a.x) //edit: to get same semantics, you of course also need the element selector 
.ToList() 
+0

我在存儲庫中有我的'_context',所以我無法從我的課程中訪問它。另外,'進入組'會導致我這個錯誤:'無效的表達式'組'' – RandomStranger

+0

哦,很抱歉,組當然是一個用過的名字,將會修復。 – georch

+0

你的其他問題是什麼?你不能從外面訪問_context? – georch