如何在List <list <double>&gt;中找到模态值对于每个内部值?</list <double>

时间:2014-08-04 13:06:15

标签: c# linq list modal-dialog

这与我之前提出的另一个问题非常相似。我不知道如何在Linq做事,所以我需要一些帮助。我想找到List的模态值&gt;对于每个内在价值。

我有以下列表:

    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};

4 个答案:

答案 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

首先将列表转换为键值对列表,这些键值对在每个列表中添加索引信息。然后将这些列表展平为一个列表,然后按索引对此新列表进行分组。这些组按值计数排序,并为每个组返回最常用的元素。