【问题标题】:Apply the sorting sequence of actions from array A to array B, re-ordering it应用从数组 A 到数组 B 的动作排序序列,重新排序
【发布时间】:2015-08-24 08:49:38
【问题描述】:

在c#中是否可以优雅地解决以下问题?

给定两个长度相等的数组(用于存储不同的数据类型),__a 和 __b,

Vector3[] __a = new Vector3[]{new Vector3(0,0,2), new Vector3(0,0,1), new Vector3(0,0,4), new Vector3(0,0,3)};
int[] __b = new int[]{1, 2, 3, 4 };

如何对 __a 进行排序,同时对 __b 进行相应的重新排序?

可以通过 System.Array.Sort() 或例如借助 LINQ 对 __a 进行排序。

在对 __a 进行排序后,对于本示例,按 z 坐标排序,输出将如下所示: (0,0,1), (0,0,2), (0,0,3), (0,0,4)

而且,__b 应该被重新排列成: 2,1,4,3

this question might look simmilar,但在我目前的情况下,数组的大小始终相同。它们的内容不能相互比较。 相反,移动 __a 中的元素应该会导致 __b 中的相应元素发生相同的变化。

This question again relies on comparing internal variables of objects. 在本例中,我使用了 Vector3 和 int 数据类型,但实际上 __B 可以携带对自定义对象的引用,并且无法进行比较。

有没有办法“扩展” Array.Sort() 以便在重新排列 __a 时,以完全相同的方式重新排列 __b?也许有一种方法可以使用 LINQ?

【问题讨论】:

  • 谢谢@spyr03,我确实可以使用包装类来保存来自 A 的 1 个条目和来自 B 的一个条目。然后我可以创建这些包装器的数组。通过 Wrapper 的 A 条目对该数组进行排序将意味着 B 条目也被重新排列。然后,我可以遍历 B 的包装器及其条目,创建一个重新排列的 B 数组。但是在考虑是否可以以更简单的方式实现,而无需额外的外壳
  • 可能是 Array.ParallelSort() 之类的:D

标签: c# arrays linq sorting


【解决方案1】:

为此有一个specific overload of Array.Sort

使用指定的IComparer<T> 通用接口根据第一个Array 中的键对一对Array 对象(一个包含键,另一个包含相应的项)进行排序。

您需要为您的键编写这样的IComparer<T> 接口,具体取决于您要使用哪个向量组件来比较它们。这是一个假设您的第三个组件是 Z 的示例:

class ThirdComponentComparer : IComparer<Vector3>
{
    public int Comparer(Vector3 a, Vector3 b)
    {
        // Null checks first?
        return a.Z.CompareTo(b.Z);
    }
}

Array.Sort(__a, __b, new ThirdComponentComparer());

【讨论】:

  • 谢谢,这正是我所需要的。忽略了!
  • @user3593478 从关于这个问题和类似问题的其他答案来看,你不是唯一一个:)
【解决方案2】:

这有点做作,但有效:

int[] a =  { 1, 2, 3, 4 };
double[] d = { 2.0, 1.0, 4.0, 3.0 };

var sortedIntArray = d.Select((elem, index) => new { Value = elem, Index = index })
                      .OrderBy(n => n.Value)
                      .Zip(a, (first, second) => new { first, second })
                      .OrderBy(x => x.first.Index)
                      .Select(x => x.second)
                      .ToArray();

【讨论】:

  • 谢谢!所以我们将它们的元素连接在一起,按它们的前半部分对这些元组进行排序,然后将后半部分提取到一个数组中
  • @user3593478 - 是的,但首先对前半索引上的元组进行排序
【解决方案3】:

您也可以分两步完成。对 __a 进行排序,保持项目的原始索引排序。然后使用这些索引对 __b 重新排序:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {

        internal class Foo {
            public int Index { get; set; }

            public Foo(int index)
            {
                this.Index = index;
            }
        }

        internal class Bar {
            public string Text { get; set; }

            public Bar(string text)
            {
                this.Text = text;
            }
        }

        static void Main(string[] args)
        {
            Foo[] __a = new[] { new Foo(4), new Foo(3), new Foo(2), new Foo(1), new Foo(0) };
            Bar[] __b = new[] { new Bar("Y"), new Bar("Z"), new Bar("Z"), new Bar("Y"), new Bar("X") };

            // Sort all foos, by Value, keeping the original index.
            var sorted = __a.Select((x, i) => new KeyValuePair<Foo, int>(x, i)).OrderBy(x => x.Key.Index);

            // Retrieve the sorted foos as a Foo[].
            var sortedFoos = sorted.Select(x => x.Key).ToArray();

            // Pick the bars according to the original index of the foos.
            var sortedBars = sorted.Select(x => __b[x.Value]).ToArray();

            Console.WriteLine(string.Concat(sortedFoos.Select(x => x.Index)));
            Console.WriteLine(string.Concat(sortedBars.Select(x => x.Text)));
        }
    }
}

01234
XYZZY
Press any key to continue . . .

【讨论】:

  • 谢谢!成对加入,排序然后提取似乎是一种非常合理的方法:D
猜你喜欢
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
  • 2012-02-14
  • 2015-02-13
  • 1970-01-01
相关资源
最近更新 更多