2010-06-24 58 views
1

我不確定CopyMost是否是在此使用的正確術語,但它是我使用的客戶端(「CopyMost數據協議」)的術語。聽起來像他想要的模式?我有一組數據:LINQ(模式)中的返回模態平均值

Increment Value 
.02   1 
.04   1 
.06   1 
.08   2 
.10   2 

我需要返回哪個值出現最「CopyMost」。在這種情況下,值是1.現在我已經計劃爲IEnumerable編寫一個擴展方法來爲整數值執行此操作。 Linq內置了哪些已經很容易實現的功能?抑或是最適合我寫這將是這個樣子

records.CopyMost(x => x.Value); 

編輯

看起來像我期待的模態平均的擴展方法。我已經提供了一個更新的答案,允許一個tiebreaker條件。它的意思是像這樣使用,並且是通用的。

records.CopyMost(x => x.Value, x => x == 0); 

在這種情況下x.Value將是int,如果0的計數是一樣的1秒和3秒的計數,這將搶七的0

回答

4

嗯,這裏是一個選項:

var query = (from item in data 
      group 1 by item.Value into g 
      orderby g.Count() descending 
      select g.Key).First(); 

基本上我們正在使用GroupBy到組由值 - 但所有我們爲每個組感興趣的是該組的大小關鍵(這是原始值)。我們按大小對組進行排序,並採用第一個元素(元素最多的元素)。

這有幫助嗎?

+0

除了1.「group 1 by item.Value into g」之外,這一切都是有道理的。爲什麼是1?爲什麼不是項目?我測試過,他們都得到相同的結果。我知道1因爲某種原因可能更好,但我想明白爲什麼。 – jsmith 2010-06-24 15:16:39

+1

@jsmith:只是爲了表明你真的不關心組內的值。你甚至可以使用'(byte)1'來提高效率:) – 2010-06-24 15:18:15

+0

那麼如果我使用不同的值,比如'group 2',會發生什麼? – msarchet 2010-06-24 15:25:44

2

喬恩擊敗了我,但你要找的是Modal Average

編輯:

如果我在想,這是模式的平均正確的,你需要那麼下面應該做的伎倆:

var i = (from t in data 
     group t by t.Value into aggr 
     orderby aggr.Count() descending 
     select aggr.Key).First(); 
0

該方法已在我的代碼經過了幾次更新這些年來。它變成了一個非常重要的方法,與它所使用的方法有很大的不同。我希望提供最新的版本,以防止任何人希望將CopyMost或模態平均值添加爲linq擴展名。

有一件事我不認爲我需要的是某種決勝者。現在我已經超負荷的方法來包括一個tiebreaker。

public static K CopyMost<T, K>(this IEnumerable<T> records, Func<T, K> propertySelector, Func<K, bool> tieBreaker) 
{ 
    var grouped = records.GroupBy(x => propertySelector(x)).Select(x => new { Group = x, Count = x.Count() }); 
    var maxCount = grouped.Max(x => x.Count); 
    var subGroup = grouped.Where(x => x.Count == maxCount); 

    if (subGroup.Count() == 1) 
     return subGroup.Single().Group.Key; 
    else 
     return subGroup.Where(x => tieBreaker(x.Group.Key)).Single().Group.Key; 
} 

上面假設用戶輸入了一個合法的tiebreaker條件。您可能想要檢查tiebreaker是否返回有效值,如果不是,則拋出異常。這是我常用的方法。

public static K CopyMost<T, K>(this IEnumerable<T> records, Func<T, K> propertySelector) 
{ 
    return records.GroupBy(x => propertySelector(x)).OrderByDescending(x => x.Count()).Select(x => x.Key).First(); 
}