这与我之前提出的另一个问题非常相似。我不知道如何在Linq做事,所以我需要一些帮助。我想找到List的模态值>对于每个内在价值。
我有以下列表:
List<List<double>> myFullList = new List<List<double>>();
for(int i = 1; i <= numberOfLoops; i++)
{
List<double> myInnerList = new List<double>();
for(int i = 1; i <= 10; i++)
{
// Populate inner list with random numbers
myInnerList.Add(double myRandomNumber);
}
// Add the inner list to the full list
myFullList.Add(myInnerList);
}
列表应如下所示:
myFullList[0] = {rand#1,rand#2,rand#3,...,rand#10}
myFulllist[1] = {rand#1,rand#2,rand#3,...,rand#10}
.
.
.
.
myFulllist[1] = {rand#1,rand#2,rand#3,...,rand#10}
我需要找到该数据的MODAL VALUE,以形成一个如下所示的单个列表:
List<double> mode= new List<double>();
mode= {mode#1, mode#2........mode#10}
此输出变量将在内部列表中找到相同“行”数据的数据模式。
简单示例:
innerList[0] = {1.00,2.00,3.00};
innerList[1] = {3.00,2.00,8.00};
innerList[2] = {3.00,9.00,1.00};
innerList[3] = {3.00,1.00,1};
fullList = {innerList[0], innerList[1], innerList[2], innerList[3]};
modeList = {3,2,1};
答案 0 :(得分:1)
不是最优雅的方式,但可能更容易理解。它已经成功测试:)
class Program
{
static void Main(string[] args)
{
Random rnd = new Random();
int numberOfLoops = 10;
List<List<int>> myFullList = new List<List<int>>();
for (int i = 0; i < numberOfLoops; i++)
{
List<int> myInnerList = new List<int>();
for (int j = 0; j < 10; j++)
{
// Populate inner list with random numbers
myInnerList.Add(rnd.Next(0, 10));
}
// Add the inner list to the full list
myFullList.Add(myInnerList);
}
myFullList = Transpose<int>(myFullList);
List<int> result = new List<int>();
foreach (List<int> subList in myFullList)
result.Add(Mode(subList));
//TO-DO: linq version!
//List<int> result = myFullList.ForEach(num => Mode(num));
}
public static int Mode(List<int> x)
{
int mode = x.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;
return mode;
}
public static List<List<T>> Transpose<T>(List<List<T>> lists)
{
var longest = lists.Any() ? lists.Max(l => l.Count) : 0;
List<List<T>> outer = new List<List<T>>(longest);
for (int i = 0; i < longest; i++)
outer.Add(new List<T>(lists.Count));
for (int j = 0; j < lists.Count; j++)
for (int i = 0; i < longest; i++)
outer[i].Add(lists[j].Count > i ? lists[j][i] : default(T));
return outer;
}
}
答案 1 :(得分:0)
这很简单,这里是代码(对不起,还没有完全测试过,但最好开始):
public static class ModalHelper
{
public static List<double> GetModals(List<List<double>> source)
{
return source.Select(list => list.Sum()/list.Count).ToList();
}
}
答案 2 :(得分:0)
这样的事情应该给出模式:
var temp = myFullList.SelectMany(l => l).GroupBy(all => all).Select(result => new
{
Value = result.Key,
Count = result.Count()
}).OrderByDescending(t => t.Count);
说明:
来自MSDN - SelectMany
将序列的每个元素投影到IEnumerable并展平 得到的序列成一个序列。
因此它给出了子列表中的每个小数。然后我们按小数本身对其进行分组,并选择每个小数及其值。最后,我们按计数排序,首先给出最常出现的小数。
根据Robert S的评论进行编辑
上面的代码似乎并不是必需的。正如Robert S所指出的那样,代码在List<List<double>>
中给出了所有数字的模式,但问题是如何从每个列中获取模式。
以下代码应该为每列提供模式。请注意,此代码忽略重复;如果出现多个号码,则第一个号码的出现次数相同:
var result1 = myFullList[0].Select((l, i) => new
{
Column = i,
Mode = myFullList.GroupBy(fl => fl[i]).OrderByDescending(t => t.Count()).Select(t => t.Key).FirstOrDefault()
});
foreach (var item in result1)
{
Console.WriteLine(string.Format("{0} {1}", item.Column, item.Mode));
}
代码使用Select
的重载来获取元素的索引(OP定义中的列)。然后它将该项目的每个项目分组。请注意,myFullList
上没有边界检查,但在生产代码中应该有。
如果重复是一个问题,我们需要两个步骤:
var temp2 = myFullList[0].Select((l, i) => new
{
Column = i,
Mode = myFullList.GroupBy(fl => fl[i]).Select(t => new { Number = t.Key, Count = t.Count() }).OrderByDescending(a => a.Count)
});
var result2 = temp2.Select(t => new
{
Column = t.Column,
Mode = t.Mode.Where(m => m.Count == t.Mode.Max(tm => tm.Count))
});
foreach (var item in result2)
{
for (int i = 0; i < item.Mode.Count(); i++)
{
Console.WriteLine(string.Format("{0} {1}", item.Column, item.Mode.ElementAt(i)));
}
}
在上面的代码中,temp2.Mode
将包含一个匿名对象的IEnumerable,其中包含该数字的出现次数和次数。然后通过抓取计数与计数最大值匹配的每个项目填充result2
。
鉴于输入:
myFullList.Add(new List<double> { 1.00, 2.00, 3.00 });
myFullList.Add(new List<double> { 3.00, 2.00, 3.00 });
myFullList.Add(new List<double> { 3.00, 9.00, 1.00 });
myFullList.Add(new List<double> { 3.00, 1.00, 1 });
第一个代码输出
0 3
1 2
2 3
和第二个输出
0 3
1 2
2 3
2 1
请注意,第2列有两个输出,因为3和1同样受欢迎。
答案 3 :(得分:0)
这个linq查询应该可以解决这个问题
var result = list.Select<List<double>, List<KeyValuePair<int, double>>>(sub =>
{
List<KeyValuePair<int, double>> elems = new List<KeyValuePair<int, double>>(sub.Count);
for (int i = 0; i < sub.Count; ++i)
elems.Add(new KeyValuePair<int, double>(i, sub[i]));
return elems;
}).SelectMany((x) => x).GroupBy((x) => x.Key).Select<IGrouping<int, KeyValuePair<int, double>>, double>(x =>
{
var y = x.GroupBy(g => g.Value).OrderByDescending(g => g.Count());
return y.First().First().Value;
});
以下是一个例子:
static void Main(string[] args)
{
List<List<double>> list = new List<List<double>>();
list.Add(new List<double> { 1.00, 2.00, 3.00 });
list.Add(new List<double> { 3.00, 2.00, 8.00 });
list.Add(new List<double> { 3.00, 9.00, 1.00 });
list.Add(new List<double> { 3.00, 1.00, 1 });
var result = list.Select<List<double>, List<KeyValuePair<int, double>>>(sub =>
{
List<KeyValuePair<int, double>> elems = new List<KeyValuePair<int, double>>(sub.Count);
for (int i = 0; i < sub.Count; ++i)
elems.Add(new KeyValuePair<int, double>(i, sub[i]));
return elems;
}).SelectMany((x) => x).GroupBy((x) => x.Key).Select<IGrouping<int, KeyValuePair<int, double>>, double>(x =>
{
var y = x.GroupBy(g => g.Value).OrderByDescending(g => g.Count());
return y.First().First().Value;
});
foreach (double val in result)
Console.Write(val + " ");
Console.WriteLine();
}
这是ideone的实时版本:http://ideone.com/ye2EhG
首先将列表转换为键值对列表,这些键值对在每个列表中添加索引信息。然后将这些列表展平为一个列表,然后按索引对此新列表进行分组。这些组按值计数排序,并为每个组返回最常用的元素。