简体   繁体   English

根据值列出3个列表

[英]Sort 3 list according to their values

I have 3 lists that contain a arbitray number of doubles. 我有3个包含任意数量的双精度的列表。 Now I want to compare this lists against each others and sort them. 现在我想将这个列表与其他列表进行比较并对它们进行排序。 All the list have the same length. 所有列表都具有相同的长度。

The relationship of sorting is: 排序的关系是:

Compare every element. 比较每个元素。 The list which has more elements that greater as the other is higher ordered. 具有更多元素的列表,其他更高的元素。 I wrote an implementation for two lists: 我为两个列表编写了一个实现:

public static bool isGreater(List<double> first, List<double> second)
        {
            int firstCounter = 0;
            int secondCounter = 0;

            for (int i = 0; i < first.Count; i++)
            {
                if (first.ElementAt(i) > second.ElementAt(i))
                {
                    firstCounter++;
                }
                else if (first.ElementAt(i) < second.ElementAt(i))
                {
                    secondCounter++;
                }
            }

            if (firstCounter > secondCounter)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

But how can I adapt this code for 3, or even n lists? 但是,如何为3个甚至n个列表调整此代码?

What you need to do sort() an collection of lists based on your definition of ordering. 你需要做什么sort()根据你的订购定义列表的集合。 You should be able to use the standard sort and supply it your custom ordering function. 您应该能够使用标准排序并为其提供自定义排序功能。

Algorithm would be something like: 算法类似于:

  1. Create a array of lists you want to sort. 创建要排序的列表数组。
  2. Call the standard sort() method on Arrays, use the routine you defined above as the comparator function. 在Arrays上调用标准的sort()方法,使用上面定义的例程作为比较器函数。

EDIT: This algorithm should give you the max in O(MN lgN) (N lists each of size M). 编辑:这个算法应该给你最大的O(MN lgN)(N列出每个大小M)。 I know of a sligtly faster (logarithmic factors) randomized algorithm to find the max. 我知道一个更快速(对数因子)随机算法来找到最大值。 You can read about it here . 你可以在这里阅读它。 I would not recommend implementing this algorithm unless you have an enormously large number of lists to process. 除非您要处理大量的列表,否则我不建议实施此算法。

You should be able to do this using LINQ and a custom IComparer for IEnumerable<double> . 您应该可以使用LINQ和IEnumerable<double>的自定义IComparer来完成此操作。

public class EnumerableDoubleComparer : IComparer<IEnumerable<double>>
{
    public int Compare( IEnumerable<double> a, IEnumerable<double> b )
    {
        var counts = a.Select( (k,i) => new { Value = k, Index = i } )
                      .Join( b.Select( (k,i) => new { Value = k, Index = i } ),
                             outer => outer.Index,
                             inner => inner.Index,
                             (outer,inner) => outer.Value > inner.Value
                                                  ? "A"
                                                  : (inner.Value > outer.Value
                                                        ? "B"
                                                        : "" ) )
                      .GroupBy( listID => listID )
                      .Select( g => new { g.Key, Count = g.Count() } );

        // you could also use SingleOrDefault on the collection and check for null
        var aCount = counts.Where( c => c.Key == "A" )
                           .Select( c => c.Count )
                           .SingleOrDefault();
        var bCount = counts.Where( c => c.Key == "B" )
                           .Select( c => c.Count )
                           .SingleOrDefault();

        return aCount - bCount;
    }
}

Used as: 用作:

var a = new double[] { 1, 1 };
var b = new double[] { 2, 2 };
var c = new double[] { 3, 3 };

var lists = new List<IEnumerable<double>> { a, c, b };

var ordered = lists.OrderByDescending( l => l, new EnumerableDoubleComparer() );

First wouldn't it be easier to use a collection that is already sorted? 首先使用已经排序的集合会不会更容易?

You can use a Sorted Dictonary to do that. 你可以使用Sorted Dictonary来做到这一点。

With regards to your question of how to apply it to n-lists use recursion just use a collection and keep track of the last result. 关于如何将其应用于n-lists的问题,使用递归只需使用集合并跟踪最后的结果。 This will let you compare the first and third list for example, if the result of the first iteration of your recursive function, returns the first list. 例如,如果递归函数的第一次迭代的结果返回第一个列表,则可以比较第一个和第三个列表。

Use an array to hold counter for each list. 使用数组来保存每个列表的计数器。

If you have n lists. 如果你有n个列表。 Your array is Counter 你的阵列是Counter

 void SortLists(List<List<double>> lists)
 {
 int[] counter = new int[lists.Count];

 for (int i = 0; i < lists[0].Count; i++)
 {
     double MaxValue = double.MinValue;
     int winningList = 0;

     for (int j = 0; j < lists.Count; j++)
     {
        if(lists[j].ElementAt(i) > MaxValue )
        {
            MaxValue = lists[j].ElementAt(i);
            winningList = j;
        }
     }

     counter[winningList]++;
 }

 // sort the counter array, in effect your lists are sorted.
 }
var list11 = new List<double> { 1, 2, 3 };
var list22 = new List<double> { 4, 5, 3 };
var list33 = new List<double> { 4, 1, 0 };

int acounter = 0, bcounter = 0, ccounter;
list11.Select((o, i) => new { a = list11[i], b = list22[i] })
    .Aggregate(0, (init, item) => item.a > item.b
                                        ? acounter++
                                        : item.a == item.b
                                            ? bcounter
                                            : bcounter++);
if (acounter > bcounter)
{
    //Do the same for list11 and list33
}
else
{
    //Do the same for list22 and list33 
}

you can refactor it and write a function for two list and call that for every pair that you want.

I've eddited just a little your method and added another one: 我只想了一点你的方法并添加了另一个:

private static List<double> GetGreater(List<double> first, List<double> second)
{
    int firstCounter = 0;
    int secondCounter = 0;

    for (int i = 0; i < first.Count; i++)
    {
        if (first.ElementAt(i) > second.ElementAt(i))
        {
            firstCounter++;
        }
        else if (first.ElementAt(i) < second.ElementAt(i))
        {
            secondCounter++;
        }
    }

    // return the greater list instead of bool
    return (firstCounter > secondCounter ? first : second);
}


public static List<double> Greater(params List<double>[] p)
{
    // assumes the first list is the greater, then check the others
    // this method assumes you will always pass at least 2 lists

    List<double> greater = p[0];

    for (var i = 1; i < p.Length; ++i)
    {
        greater = GetGreater(greater, p[i]);
    }

    return greater;
}

static void Main(string[] args)
{
    // lists used for this test
    var l1 = new List<double>() { 1, 222, 3 };
    var l2 = new List<double>() { 1, 2, 4 };
    var l3 = new List<double>() { 11, 222, 333 };

    var l4 = Greater(l1, l2, l3); // l3
}

It sounds to me like you have an "outer" list of "inner" lists, and you want to sort the "outer" list. 听起来像你有一个“内部”列表的“外部”列表,并且你想要对“外部”列表进行排序。 You can do that: 你可以这样做:

// Set up some input data
var outerList = new List<List<double>>();
outerList.Add(new List<double> { 2.0, 3.0, 3.0 });
outerList.Add(new List<double> { 1.0, 2.0, 3.0 });
outerList.Add(new List<double> { 2.0, 2.0, 3.0 });

// Sort the outer list
outerList.Sort((first, second) => isGreater(first, second) ? 1 : -1);

Actually, you would probably be better off changing isGreater (which can't return a "both lists are equal" result, which could confuse Sort) to a CompareLists function that returns -1 if the first argument is less than the second, 1 if the first argument is greater than the second, and 0 if they're equal. 实际上,你可能最好更改isGreater(它不能返回“两个列表都相等”的结果,这可能会混淆Sort)一个CompareLists函数,如果第一个参数小于第二个,则返回-1,如果是第一个参数大于第二个参数,如果它们相等则为0。 Then you could just call: 然后你可以打电话:

outerList.Sort(CompareLists);

As long as the number of elements in each list is the same and known, here's a little example I worked up: 只要每个列表中的元素数量相同且已知,这是我编写的一个小例子:

const int listSize = 6;

List<int> one = new List<int> { 0, 1, 2, 3, 4, 5 };
List<int> two = new List<int> { 10, 1, 9, 2, 8, 3 };
List<int> three = new List<int> { 5, 5, 5, 5, 5, 5 };

Dictionary<List<int>, int> lists = new Dictionary<List<int>, int>()
{
    {one, 0},
    {two, 0},
    {three, 0}
};

for (int i = 0; i < listSize; i++)
{
    var sortedAtIndex = lists.Keys.OrderByDescending(k => k[i]);
    lists[sortedAtIndex.ElementAt(0)]++;
}

// And to show you that it works...
foreach (var element in lists.OrderByDescending(k => k.Value)
    .Select(k => k.Key))
{
    Console.WriteLine("{0}", lists[element]);
}

The multiplicity of lists is an illusion - there is only one list, but each item has an attribute identifying which list it comes from. 列表的多样性是一种幻觉 - 只有一个列表,但每个项目都有一个属性,用于标识它来自哪个列表。

Merge the lists, sort, then split back to their original lists. 合并列表,排序,然后拆分回原始列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM