简体   繁体   English

如何在java中对多个数组进行排序

[英]How to sort multiple arrays in java

I'm trying to sort three arrays by lexicographical order. 我试图按字典顺序对三个数组进行排序。 The arrays are related to each other by a common array. 阵列通过公共阵列彼此相关。 It's easier to explain if I demonstrate: 如果我证明,它更容易解释:

int[] record = new int[4];
String [] colors = {"blue", "yellow", "red", "black"};
String [] clothes = {"shoes", "pants", "boots", "coat"};

When printed on the console, I would like them to be put in three columns similar to below: 在控制台上打印时,我希望将它们放在类似下面的三列中:

Unsorted: 未排序:

Record  Color   Clothes
0       blue    shoes
1       yellow  pants
2       red     boots
3       black   coat

Sorted by Color: 按颜色排序:

Record  Color   Clothes
3       black   coat
0       blue    shoes
2       red     boots
1       yellow  pants

Sorted by Clothes: 按衣服排序:

Record  Color   Clothes
2       red     boots
3       black   coat
1       yellow  pants
0       blue    shoes

I found a previous answer similar to my scenario, but it compared integers instead of strings, and I'm having trouble using the compareTo() method and Arrays.sort() to arrive at my desired output. 我找到了一个类似于我的场景的先前答案,但是它比较了整数而不是字符串,而我在使用compareTo()方法和Arrays.sort()来达到我想要的输出时遇到了麻烦。

Any help would be appreciated! 任何帮助,将不胜感激!

In some cases it doesn't make much sense to create a new class just to do sorting. 在某些情况下,创建一个新类只是为了进行排序没有多大意义。

Here, is a function that can be used to sort an any number of arbitrarily typed lists ( List<?> ) based on a key list ( List<T implements Comparable> ). 这里,是一个函数,可用于根据键列表( List<T implements Comparable> )对任意数量的任意类型列表( List<?> )进行排序。 Ideone Example here . 这里是Ideone示例


Usage 用法

Here is an example of how you can use the function to sort multiple lists of arbitrary types: 下面是一个如何使用该函数对任意类型的多个列表进行排序的示例:

List<Integer> ids = Arrays.asList(0, 1, 2, 3);
List<String> colors = Arrays.asList("blue", "yellow", "red", "black");
List<String> clothes = Arrays.asList("shoes", "pants", "boots", "coat");

// Sort By ID
concurrentSort(ids, ids, colors, clothes);

// Sort By Color
concurrentSort(colors, ids, colors, clothes);

// Sort By Clothes
concurrentSort(clothes, ids, colors, clothes);

Output: 输出:

// Sorted By ID:
ID:      [0, 1, 2, 3]
Colors:  [blue, yellow, red, black]
Clothes: [shoes, pants, boots, coat]

// Sorted By Color:
ID:      [3, 0, 2, 1]
Colors:  [black, blue, red, yellow]
Clothes: [coat, shoes, boots, pants]

// Sorted By Clothes:
ID:      [2, 3, 1, 0]
Colors:  [red, black, yellow, blue]
Clothes: [boots, coat, pants, shoes]

Code

An Ideone Example can be found here which includes validation of parameters and a test case. 这里可以找到Ideone示例其中包括参数验证和测试用例。

public static <T extends Comparable<T>> void concurrentSort(
                                        final List<T> key, List<?>... lists){
    // Create a List of indices
    List<Integer> indices = new ArrayList<Integer>();
    for(int i = 0; i < key.size(); i++)
        indices.add(i);

    // Sort the indices list based on the key
    Collections.sort(indices, new Comparator<Integer>(){
        @Override public int compare(Integer i, Integer j) {
            return key.get(i).compareTo(key.get(j));
        }
    });

    // Create a mapping that allows sorting of the List by N swaps.
    // Only swaps can be used since we do not know the type of the lists
    Map<Integer,Integer> swapMap = new HashMap<Integer, Integer>(indices.size());
    List<Integer> swapFrom = new ArrayList<Integer>(indices.size()),
                  swapTo   = new ArrayList<Integer>(indices.size());
    for(int i = 0; i < key.size(); i++){
        int k = indices.get(i);
        while(i != k && swapMap.containsKey(k))
            k = swapMap.get(k);

        swapFrom.add(i);
        swapTo.add(k);
        swapMap.put(i, k);
    }

    // use the swap order to sort each list by swapping elements
    for(List<?> list : lists)
        for(int i = 0; i < list.size(); i++)
            Collections.swap(list, swapFrom.get(i), swapTo.get(i));
}

NOTE: The running time is O(mlog(m) + mN) where m is the length of the list and N is the number of lists. 注意:运行时间为O(mlog(m) + mN) ,其中m是列表的长度, N是列表的数量。 Usually m >> N so the running time is not more significant than sorting only the key O(mlog(m)) . 通常m >> N所以运行时间并不比仅排序键O(mlog(m))更重要。

Since Record , Color and Clothes seem to belong together, I would suggest moving them together in a custom Object, eg 由于RecordColorClothes似乎属于一体,我建议将它们放在一个自定义对象中,例如

public class ClothesItem {
    int record;
    String color;
    String clothes;
}  

Then you can make different Comparator s to do the different variants of sorting. 然后你可以让不同的Comparator来做不同的排序变种。

If you need to preserve your current structure with multiple arrays, @Jherico has a sorting solution here that gets an array of the sorted indexes, which should make it trivial to get to your wanted result. 如果您需要使用多个数组保留当前结构, @ Jackson在这里有一个排序解决方案,它可以获得一系列已排序的索引,这样可以轻松获得您想要的结果。

Alright, here's what it looks like in final form. 好吧,这是最终形式的样子。

// ColorClothes.java

import java.util.*;


public class ColorClothes
{
public int record;
public String color;
public String clothes;

public static void main(String[] args)
{
    Initialize();
}

public ColorClothes(int record, String color, String clothes)
{
    this.record = record;
    this.color = color;
    this.clothes = clothes;
}

public static void Initialize()
{
    List<ColorClothes> list = new ArrayList();
    list = CreateList();

    Sort(list, "Unsorted", 1);
    Sort(list, "\nSortedByColor", 2);
    Sort(list, "\nSortedByClothes", 3);
    Sort(list, "\nSortedByRecord", 4);
}


public static List<ColorClothes> CreateList()
{
    List<ColorClothes> list = new ArrayList();
    list.add(new ColorClothes(1, "blue  ", "shoes"));
    list.add(new ColorClothes(0, "yellow", "pants"));
    list.add(new ColorClothes(3, "red   ", "boots"));
    list.add(new ColorClothes(2, "black ", "coat"));

    return list;
}

public static void Print(List<ColorClothes> list)
{
    for (ColorClothes item : list)
    {
        System.out.println(item.record + "    " + item.color + "   " + item.clothes);
    }
}

public static void Sort(List<ColorClothes> list, String string, int choice)
{
    System.out.println(string + "\n");

    switch (choice)
    {
    case 1:
        break;
    case 2:
        Collections.sort(list, new ColorComparator());
        break;
    case 3:
        Collections.sort(list, new ClothesComparator());
        break;
    case 4:
        Collections.sort(list, new RecordComparator());
        break;
    }

    Print(list);
}

} // End class.

// ColorComparator.java

import java.util.Comparator;

 class ColorComparator implements Comparator
 {
public int compare(Object str1, Object str2)
{
    String str1Color = ((ColorClothes)str1).color;
    String str2Color = ((ColorClothes)str2).color;

    return str1Color.compareTo(str2Color);

}
}// End class.

// ClothesComparator.java

import java.util.Comparator;


class ClothesComparator implements Comparator
{
public int compare(Object str1, Object str2)
{
    String str1Clothes = ((ColorClothes)str1).clothes;
    String str2Clothes = ((ColorClothes)str2).clothes;

    return str1Clothes.compareTo(str2Clothes);

}
} // End class.

// RecordComparator.java

import java.util.Comparator;


public class RecordComparator implements Comparator 
{
public int compare(Object rec1, Object rec2)
{
    int rec1Rec = ((ColorClothes)rec1).record;
    int rec2Rec = ((ColorClothes)rec2).record;

    if(rec1Rec > rec2Rec)
    {
        return 1;
    }
    else if(rec1Rec < rec2Rec)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}
}// End class.

Console Output 控制台输出

Unsorted

1    blue     shoes
0    yellow   pants
3    red      boots
2    black    coat

SortedByColor

2    black    coat
1    blue     shoes
3    red      boots
0    yellow   pants

SortedByClothes

3    red      boots
2    black    coat
0    yellow   pants
1    blue     shoes

SortedByRecord

0    yellow   pants
1    blue     shoes
2    black    coat
3    red      boots

I am not sure about sorting multiple arrays at once; 我不确定一次排序多个数组; looking at the use case used by you this looks like a contender where all 3 attributes can be combined into an object and then the array of objects can be sorted in multiple ways. 查看您使用的用例,这看起来像一个竞争者,其中所有3个属性可以组合成一个对象,然后对象数组可以以多种方式排序。

Are you sure that you need to have 3 arrays? 你确定需要3个阵列吗?

Does an array of ColoredCloth would work for you like: ColoredCloth数组是否适用于您:

class ColoredCloth implements Comparable<ColoredCloth>{
    int id;
    String color;
    String cloth;
}

and define a couple of Comparators to sort by color and cloth . 并定义几个Comparatorscolorcloth排序。

Sort the arrays in-directly. 直接对数组进行排序。 Index all your arrays and sort only the index-array of the desired array. 索引所有数组并仅排序所需数组的索引数组。 Take a look at the solution in this SO post . 看看这篇SO帖子中的解决方案。 This will keep your arrays consistent. 这将使您的阵列保持一致。 I'm not sure if it's easy to extrapolate this to sorting N-arrays in sync though, but it should give you an idea of how to approach the problem in case you want to stick with having your data distributed in multiple arrays. 我不确定是否可以很容易地将其推断为同步排序N阵列,但它应该让您了解如何解决问题,以防您希望将数据分布在多个阵列中。 As several people already pointed out, grouping the data in a single object is a good approach. 正如几位人士已经指出的那样,将数据分组到一个对象中是一种很好的方法。

Here is how I sort two or more string arrays of the same length, so that the first array is in order and the other arrays match that order: 下面是我如何对两个或多个相同长度的字符串数组进行排序,以便第一个数组按顺序排列,其他数组与该顺序匹配:

public static void order(String[]... arrays)
{
    //Note: There aren't any checks that the arrays
    // are the same length, or even that there are
    // any arrays! So exceptions can be expected...
    final String[] first = arrays[0];

    // Create an array of indices, initially in order.
    Integer[] indices = ascendingIntegerArray(first.length);

    // Sort the indices in order of the first array's items.
    Arrays.sort(indices, new Comparator<Integer>()
        {
            public int compare(Integer i1, Integer i2)
            {
                return
                    first[i1].compareToIgnoreCase(
                    first[i2]);
            }
        });

    // Sort the input arrays in the order
    // specified by the indices array.
    for (int i = 0; i < indices.length; i++)
    {
        int thisIndex = indices[i];

        for (String[] arr : arrays)
        {
            swap(arr, i, thisIndex);
        }

        // Find the index which references the switched
        // position and update it with the new index.
        for (int j = i+1; j < indices.length; j++)
        {
            if (indices[j] == i)
            {
                indices[j] = thisIndex;
                break;
            }
        }
    }
    // Note: The indices array is now trashed.
    // The first array is now in order and all other
    // arrays match that order.
}

public static Integer[] ascendingIntegerArray(int length)
{
    Integer[] array = new Integer[length];
    for (int i = 0; i < array.length; i++)
    {
        array[i] = i;
    }
    return array;
}

public static <T> void swap(T[] array, int i1, int i2)
{
    T temp = array[i1];
    array[i1] = array[i2];
    array[i2] = temp;
}

If you want to do this with arrays of other types then you will need to refactor this somewhat. 如果你想用其他类型的数组做这个,那么你需要稍微重构一下。 Alternatively, for an integer array to be sorted along with string arrays you could convert the integers to strings. 或者,对于要与字符串数组一起排序的整数数组,可以将整数转换为字符串。

I suggest you to create a class as below 我建议你创建一个类,如下所示

class Dress {
  public int record;
  public String color;
  public String clothes;
}

Maintain the list of dresses as below 保持礼服清单如下

List<Dress> dressCollection = new ArrayList<Dress>();

Implement comparator based on color and clothes. 根据颜色和衣服实施比较器。

List<Dress> resultBasedOnColor = Collections.sort(dressCollection, new Comparator<Dress>() {
   public int compareTo(Dress obj1, Dress obj2) {
     return obj1.color.compareTo(obj2.color);
 }

});

Left sorting based on clothes as exercise for question owner. 基于衣服的左排序作为问题所有者的练习。

Put the data into a custom class like @SiB: 将数据放入像@SiB这样的自定义类中:

class ColoredClothes {
    int id;
    String color;
    String cloth;
}

Then, put each instance of this class into a TreeMap with the color as the key (or cloth name depending what you want to sort by): 然后,将此类的每个实例放入一个以颜色作为键的TreeMap(或根据您要排序的布料名称):

TreeMap<String,ColoredClothes> sortedCloth= new TreeMap<String,ColoredClothes>();
//loop through arrays and put new ColoredClothes into Map

Then get the sorted values like so: 然后获取排序值,如下所示:

Collection<ColoredClothes> values = sortedCloth.values();

You can iterate through these in order by using values.iterator() 您可以使用values.iterator()按顺序遍历这些

Thanks for the help guys. 谢谢你的帮助。

I was so fixed on using arrays and sorting those arrays (since that's what was required of me), that I didn't even think about creating objects instead. 我是如此固定使用数组并对这些数组进行排序(因为这是我所需要的),我甚至没有考虑过创建对象。

With this simple program, it'll allow you to create an object and sort the fields within the object. 使用这个简单的程序,它将允许您创建一个对象并对对象中的字段进行排序。 The colors and clothes were just an example I was using. 颜色和衣服只是我使用的一个例子。

Here's my completed code below: 这是我在下面完成的代码:

// ColorClothes.java

import java.util.*;


public class ColorClothes
{
public int record;
public String color;
public String clothes;

public static void main(String[] args)
{
    Initialize();
}

public static void Initialize()
{
    ColorClothes item[] = new ColorClothes[4];

    item[0] = new ColorClothes();
    item[0].record = 0;
    item[0].color = "blue";
    item[0].clothes = "shoes";

    item[1] = new ColorClothes();
    item[1].record = 1;
    item[1].color = "yellow";
    item[1].clothes = "pants";

    item[2] = new ColorClothes();
    item[2].record = 2;
    item[2].color = "red";
    item[2].clothes = "boots";

    item[3] = new ColorClothes();
    item[3].record = 3;
    item[3].color = "black";
    item[3].clothes = "coat";

    System.out.println("Unsorted");

    for(int i = 0; i < item.length; i++)
    {
        System.out.println(item[i].record + "     " + item[i].color + "     " + item[i].clothes);
    }

    System.out.println("\nSorted By Color\n");

    Arrays.sort(item, new ColorComparator());

    for(int i = 0; i < item.length; i++)
    {
        System.out.println(item[i].record + "     " + item[i].color + "     " + item[i].clothes);
    }

    System.out.println("\nSorted By Clothes\n");

    Arrays.sort(item, new ClothesComparator());

    for(int i = 0; i < item.length; i++)
    {
        System.out.println(item[i].record + "     " + item[i].color + "     " + item[i].clothes);
    }

}

}// End class.

// ColorComparator.java

import java.util.Comparator;

class ColorComparator implements Comparator
{
public int compare(Object str1, Object str2)
{
    String str1Color = ((ColorClothes)str1).color;
    String str2Color = ((ColorClothes)str2).color;

    return str1Color.compareTo(str2Color);

}
}// End class.

// ClothesComparator.java

import java.util.Comparator;


class ClothesComparator implements Comparator
{
public int compare(Object str1, Object str2)
{
    String str1Clothes = ((ColorClothes)str1).clothes;
    String str2Clothes = ((ColorClothes)str2).clothes;

    return str1Clothes.compareTo(str2Clothes);

}
} // End class.

Console Output 控制台输出

Unsorted
0     blue     shoes
1     yellow     pants
2     red     boots
3     black     coat

Sorted By Color

3     black     coat
0     blue     shoes
2     red     boots
1     yellow     pants

Sorted By Clothes

2     red     boots
3     black     coat
1     yellow     pants
0     blue     shoes

I'll add another Comparator to allow sorting by record/integers later. 我将添加另一个Comparator,以便稍后按记录/整数进行排序。 I'll also condense the code more so it's not one big block, but I'm almost done with work for the day. 我还会更加浓缩代码,因此它不是一个大块,但我几乎完成了当天的工作。

As others suggested, easier would be to sort collection of objects instead of sorting three arrays synchronously. 正如其他人所建议的那样,更容易对对象进行排序,而不是同步对三个数组进行排序。

If, for whatever reason you have to stick to sorting multiple arrays, following approach could be used - idea is to implement own variant of arrays list, which is backed by three arrays instead of one. 如果由于某种原因你必须坚持排序多个数组,可以使用以下方法 - 想法是实现自己的数组列表变体,它由三个数组而不是一个数组支持

import java.util.AbstractList;
import java.util.Collections;

public class SortMultipleArrays extends AbstractList {

    //object representing tuple from three arrays
    private static class ClothesItem implements Comparable<ClothesItem> {
        int record;
        String color;
        String clothes;

        public ClothesItem(int record, String color, String clothes) {
            this.record = record;
            this.color = color;
            this.clothes = clothes;
        }

        @Override
        public int compareTo(ClothesItem o) {
            return this.color.compareTo(o.color); //sorting by COLOR
        }
    }

    private int[] records;
    private String[] colors;
    private String[] clothes;

    public SortMultipleArrays(int[] records, String[] colors, String[] clothes) {
        this.records = records;
        this.colors = colors;
        this.clothes = clothes;
    }

    @Override
    public Object get(int index) {
        return new ClothesItem(records[index], colors[index], clothes[index]);
    }

    @Override
    public int size() {
        return records.length;
    }

    @Override
    public Object set(int index, Object element) {
        ClothesItem item = (ClothesItem) element;
        ClothesItem old = (ClothesItem) get(index);

        records[index] = item.record;
        colors[index] = item.color;
        clothes[index] = item.clothes;

        return old;
    }

    public static void main(String[] args) {
        int[] record = {0,1,2,3};
        String[] colors = {"blue", "yellow", "red", "black"};
        String[] clothes = {"shoes", "pants", "boots", "coat"};

        final SortMultipleArrays multipleArrays = new SortMultipleArrays(record, colors, clothes);
        Collections.sort(multipleArrays);

        System.out.println("Record  Color   Clothes");
        for (int i = 0; i < record.length; i++) {
            System.out.println(String.format("%8s %8s %8s", record[i], colors[i], clothes[i]));
        }
    }
}

This implementation is based on AbstractList which makes it easier to implement List interface needed for Collections.sort(...). 此实现基于AbstractList,这使得更容易实现Collections.sort(...)所需的List接口。

Note that there may be inefficiency hidden in this implementation: both get(...) and set(...) methods are creating instance of wrapper object which may cause too many object created when sorting bigger arrays. 请注意,此实现中可能隐藏效率低: get(...)set(...)方法都在创建包装器对象的实例,这可能导致在排序较大的数组时创建的对象太多。

Liked @bcorso's idea of creating swapping lists to sort any other List. 喜欢@ bcorso创建交换列表来排序任何其他List的想法。 Here's a bit more optimized version, that uses only 2 arrays instead of a Map and 3 ListArrays, and only swaps indexes that need swapping: 这是一个更优化的版本,它只使用2个数组而不是Map和3个ListArrays,只交换需要交换的索引:

public static <T extends Comparable<T>> void syncedSort(final List<T> key, List<?>... lists) {
    // Create an array of indices
    Integer[] indices = new Integer[key.size()];
    for (int i = 0; i < indices.length; i++)
        indices[i] = i;

    // Sort the indices array based on the key
    Arrays.sort(indices, new Comparator<Integer>() {
        @Override public int compare(Integer i, Integer j) {
            return key.get(i).compareTo(key.get(j));
        }
    });

    // Scan the new indices array and swap items to their new locations,
    // while remembering where original items stored.
    // Only swaps can be used since we do not know the type of the lists
    int[] prevSwaps = new int[indices.length];
    for (int i = 0; i < indices.length; i++) {
        int k = indices[i];
        while (i > k)
            k = prevSwaps[k];
        if (i != k) {
            prevSwaps[i] = k;
            for (List<?> list : lists)
                Collections.swap(list, i, k);
        }
    }
}
import java.util.Arrays;

Arrays.sort (int [])
Arrays.sort (String [])

this will sort array of Strings. 这将排序字符串数组。

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

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