3

is it possible to elegantly solve the following problem in c#?

Given two arrays of equal length (used for storing different datatypes), __a and __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 };

How can one sort __a and at the same time re-order __b accordingly?

Sorting of __a can be done through System.Array.Sort() or, for example, with the help of LINQ.

After sorting __a, for this example by the z coordinate, the output would be the following: (0,0,1), (0,0,2), (0,0,3), (0,0,4)

And, the __b should have been re-arranged into: 2,1,4,3

this question might look simmilar, but in my current case arrays are always of the same size. Their contents cannot be compared to each other. Instead, moving the elements in __a should result in the same change to the corresponding elements in __b.

This question again relies on comparing internal variables of objects. For this example, I used Vector3 and int datatypes, however, in reality __B can be carrying references to custom objects and cannot be compared.

Is there a way to "extend" the Array.Sort() so that when __a is re-arranged, the __b is re-arranged in exactly the same way? Maybe there is a way to use LINQ?

3
  • Does this help? stackoverflow.com/questions/7918080/… Commented Aug 24, 2015 at 8:52
  • thank you @spyr03, I could indeed, use a wrapper class to hold 1 entry from A, and one from B. Then I could create an array of those wrappers. Ordering this array by Wrapper's A entries would mean B entries are re-arranged as well. I could then iterate through the wrappers and their entries of B, creating an array of re-arranged Bs. But was thinking if it's achievable in a simpler way, without the extra husk Commented Aug 24, 2015 at 9:02
  • like maybe Array.ParallelSort() or something :D Commented Aug 24, 2015 at 9:04

3 Answers 3

0

There is a specific overload of Array.Sort for this.

Sorts a pair of Array objects (one contains the keys and the other contains the corresponding items) based on the keys in the first Array using the specified IComparer<T> generic interface.

You will need to write such an IComparer<T> interface for your keys, depending on which vector component you want to use to compare them. Here's an example assuming your third component is 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());
Sign up to request clarification or add additional context in comments.

2 Comments

thank you, that's exactly what I needed. Overlooked it!
@user3593478 Judging by the other answers on this and similar questions, you're not the only one :)
0

This is a bit contrived, but works:

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();

2 Comments

thank you! So we are joining their elements together, sort those tuples by their first halves, and then extracting the second halves into an array
@user3593478 - Yes, but first sorting the tuples on first half indexes
0

You can also do it using two steps. Sort __a, keeping the original indices of the items sorted. Then use those indices to re-order __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 . . .

1 Comment

thank you! Joining into pairs, sorting and then extracting seems quite a reasonable way of doing this :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.