Java - 根据另一个数组的值对一个数组进行排序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28556129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java - Sort one array based on values of another array?
提问by Reza
I have an array of Strings that are instances of a class from external code that I would rather not change.
我有一个字符串数组,它们是来自外部代码的类的实例,我不想更改。
I also have an array of ints that was generated by calling a function on each object. So I have
我还有一个 int 数组,它是通过在每个对象上调用一个函数而生成的。所以我有
A: [string1, string2, string3]
A: [string1, string2, string3]
And
和
B: [40, 32, 34]
乙: [40, 32, 34]
How do I easily sort A such that it is sorted in by the values of B. I have boost available. I want to sort A such that it is in the order:
我如何轻松地对 A 进行排序,使其按 B 的值排序。我有可用的提升。我想对 A 进行排序,使其按以下顺序排列:
[string2, string3, string1]
In javascript you could do this like:
在 javascript 中,你可以这样做:
B.sort(function(a,b){return A[B.indexOf(a)] < A[B.indexOf(b)];});
回答by Thermech
In java 8, you can do this
在 java 8 中,你可以这样做
with a lambda:
使用 lambda:
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
Or better, with Comparator:
或者更好,使用Comparator:
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] ints = new int[]{40, 32, 34};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
回答by wassgren
Short answer:I suggest that a separate class is created that holds the information about both the actual String
and the boosting (the int
). If you assume the following:
简短回答:我建议创建一个单独的类来保存有关实际String
和提升(int
)的信息。如果您假设以下内容:
public class BoostString {
int boost;
String str;
public BoostString(int boost, String str) {
this.boost = boost;
this.str = str;
}
}
Then, you can sort your array by using a Comparator
and it works especially nice with the Java 8 Streaming API.
然后,您可以使用 a 对数组进行排序Comparator
,它与 Java 8 Streaming API 一起工作得特别好。
String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};
final String[] sorted = IntStream.range(0, boosts.length)
.mapToObj(i -> new BoostString(boosts[i], strings[i])) // Create the instance
.sorted(Comparator.comparingInt(b -> b.boost)) // Sort using a Comparator
.map(b -> b.str) // Map it back to a string
.toArray(String[]::new); // And return an array
The Comparator
in the example above is created using the Comparator.comparingInt
method which is a convenient way of creating a Comparator
for ints using Java 8.
在Comparator
以上示例中,使用所创建的Comparator.comparingInt
这是一个创建的便利方式的方法Comparator
使用Java 8整数。
Explanation:Typically when comparing objects in Java you use one of the built-in sorting functions such as Collections.sort
where you provide your own Comparator
. The Comparator
interface is straightforward and looks like this:
说明:通常在 Java 中比较对象时,您会使用其中一种内置排序功能,例如Collections.sort
您在何处提供自己的Comparator
. 该Comparator
界面很简单,看起来像这样:
public interface Comparator<T> {
int compare(T o1, T o2);
// Other default methods for Java 8
}
The return value is of type int
and is described like this in the JavaDoc:
返回值属于类型int
,在 JavaDoc 中是这样描述的:
return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
当第一个参数小于、等于或大于第二个参数时,返回一个负整数、零或正整数。
This works out-of-the-box when you are sorting String
s or int
(or actually Integer
s) since they are Comparable
– they sort of have a built-in natural sorting and for String
s this is in alphabetical order and for Integers
this is sorted in ascending number order (see the JavaDocfor Comparable
).
当您对String
s 或int
(或实际上Integer
s)进行排序时,这是开箱即用的,因为它们Comparable
具有内置的自然排序,对于String
s,这是按字母顺序排列的,Integers
因此按升序排序顺序(见的JavaDoc的Comparable
)。
On a side note, there are other "pair" or "tuple" implementations available if you are using 3rd party libraries. You do not have to create your own "pair" of a String
and int
. One example is the Pairclass from Apache Commons.
附带说明一下,如果您使用 3rd 方库,还有其他“对”或“元组”实现可用。您不必创建自己的“对” aString
和int
。一个例子是来自Apache Commons的Pair类。
回答by Alexander Torstling
You can do something similar to your JS example in old style Java (but I would recommend joining your data together in an object as @wassgren suggests):
您可以在旧式 Java 中执行类似于您的 JS 示例的操作(但我建议按照@wassgren 的建议将您的数据连接到一个对象中):
import java.util.*;
public class WeightSort {
public static void main(String[] args) {
String[] strings = new String[]{"string1", "string2", "string3"};
final int[] weights = new int[]{40, 32, 34};
final List<String> stringList = Arrays.asList(strings);
List<String> sortedCopy = new ArrayList<String>(stringList);
Collections.sort(sortedCopy, new Comparator<String>(){
public int compare(String left, String right) {
return weights[stringList.indexOf(left)] - weights[stringList.indexOf(right)];
}
});
System.out.println(sortedCopy);
}
}
回答by Reza
I solved this problem by using Comparator interface.
我通过使用 Comparator 接口解决了这个问题。
import java.util.Comparator;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class ComparatorDemo {
public static void main(String[] args) {
List<Area> metaData = Arrays.asList(
new Area("Joe", 24),
new Area("Pete", 18),
new Area("Chris", 21),
new Area("Rose",21)
);
Collections.sort(metaData, new ResultComparator());
for(int i =0 ;metaData.size()>i;i++)
System.out.println(metaData.get(i).output);
}
}
class ResultComparator implements Comparator<Area> {
@Override
public int compare(Area a, Area b) {
return a.result < b.result ? -1 : a.result == b.result ? 0 : 1;
}
}
class Area{
String output;
int result;
Area(String n, int a) {
output = n;
result = a;
}
}
回答by Guy Smith
I had a similar problem, and solved it by coding a sorting algorithm which sorted an array of measures, and made identical swaps in the array of objects. Here is the code, with tests, best wishes and no promises:
我有一个类似的问题,并通过编码一个排序算法来解决它,该算法对一系列度量进行排序,并在对象数组中进行相同的交换。这是代码,带有测试,最好的祝福,但没有承诺:
package other;
import java.util.Arrays;
import java.util.Random;
/**
* Sorts an array of objects (<code>bags</code>) by a separate array of doubles (<code>measures</code>).
* It sorts into ascending order.
* <p>
* The <code>results</code> array is always a new array.
* <p>
* The algorithm used:<ul>
* <li> Is (I believe) a merge-sort, which would mean it is stable. (I haven't tested this.)
* <li> Efficiently exploits already ordered subsequences.
* <li> Requires the allocation of eight arrays: four of the baggage type, four of doubles, each the length of the original data.
* </ul>
* <p>
* A <code>NaN</code> in the <code>measures</code> - I haven't thought about that, and don't want to.
* <p>
* There is test code at the end of the class.
*/
public class SortBaggageByDouble {
public final Object [] results ;
protected final int length ;
public SortBaggageByDouble(Object[] bags, double[] measures) {
this.length = bags.length;
if (bags.length!=measures.length) throw new IllegalArgumentException("Mismatched lengths: payload array "+bags.length+", measures array "+measures.length);
this.results = new Object[length];
Object [] bagsA = new Object[length] ;
Object [] bagsB = new Object[length] ;
Object [] bagsC = new Object[length] ;
Object [] bagsD = new Object[length] ;
double [] measuresA = new double[length] ;
double [] measuresB = new double[length] ;
double [] measuresC = new double[length] ;
double [] measuresD = new double[length] ;
System.arraycopy(bags, 0, bagsA, 0, length);
System.arraycopy(measures, 0, measuresA, 0, length);
munge(length, 0, bagsA, bagsB, bagsC, bagsD, measuresA, measuresB, measuresC, measuresD);
}
private void munge(int inLengthA, int inLengthB, Object[] inBagsA, Object[] inBagsB, Object[] outBagsC, Object[] outBagsD, double[] inMeasuresA, double[] inMeasuresB, double[] outMeasuresC, double[] outMeasuresD) {
int outLengthC = 0 ;
int outLengthD = 0 ;
int cursorA = 0 ;
int cursorB = 0 ;
boolean toC = true ;
while(outLengthC+outLengthD<length) {
boolean fromA ;
if (cursorA>=inLengthA) {
fromA = false ;
} else if (cursorB>=inLengthB) {
fromA = true ;
} else {
fromA = inMeasuresA[cursorA] <= inMeasuresB[cursorB] ;
}
double tmpMeasure = fromA ? inMeasuresA[cursorA] : inMeasuresB[cursorB] ;
Object tmpBag = fromA ? inBagsA[cursorA] : inBagsB[cursorB] ;
if (fromA) cursorA ++ ; else cursorB ++ ;
if (toC) {
if (outLengthC==0 || (outMeasuresC[outLengthC-1]<=tmpMeasure)) {
outMeasuresC[outLengthC] = tmpMeasure ;
outBagsC[outLengthC] = tmpBag ;
outLengthC ++ ;
} else {
toC = false ;
outMeasuresD[outLengthD] = tmpMeasure ;
outBagsD[outLengthD] = tmpBag ;
outLengthD ++ ;
}
} else {
if (outLengthD==0 || (outMeasuresD[outLengthD-1]<=tmpMeasure)) {
outMeasuresD[outLengthD] = tmpMeasure ;
outBagsD[outLengthD] = tmpBag ;
outLengthD ++ ;
} else {
toC = true ;
outMeasuresC[outLengthC] = tmpMeasure ;
outBagsC[outLengthC] = tmpBag ;
outLengthC ++ ;
}
}
}
if (outLengthC==length) {
System.arraycopy(outBagsC, 0, results, 0, length);
} else {
munge(outLengthC, outLengthD, outBagsC, outBagsD, inBagsA, inBagsB, outMeasuresC, outMeasuresD, inMeasuresA, inMeasuresB);
}
}
/**
* Subclass to sort strings, with a result object <code>sortedStrings</code> which is of a useful type.
*/
public static class Strings extends SortBaggageByDouble {
public final String [] sortedStrings ;
public Strings(String[] in, double[] measures) {
super(in, measures);
this.sortedStrings = new String[results.length];
for (int i=0 ; i<results.length ; i++) sortedStrings[i] = (String) results[i] ;
}
}
/**
* Tests sorting - assumes there are no duplicates among the measures.
*/
private static class NoDuplicatesTest {
private NoDuplicatesTest(String[] shuffledStrings, double[] shuffledMeasures, String[] expectedStrings) {
SortBaggageByDouble.Strings sorter = new SortBaggageByDouble.Strings(shuffledStrings, shuffledMeasures);
if (!Arrays.equals(expectedStrings, sorter.sortedStrings)) throw new RuntimeException("Test failed");
}
}
private static class MultiseedNoDuplicatesTest {
private MultiseedNoDuplicatesTest(String[] orderedStrings, double[] orderedMeasures, int[] seeds) {
int length = orderedStrings.length;
for (int seed : seeds) {
Random random = new Random(seed);
int [] shuffleIndices = new int[length] ;
for (int i=0 ; i<length ; i++) shuffleIndices[i] = i ;
for (int i=1 ; i<length ; i++) {
int j = random.nextInt(i+1); // 'j' is in the range 0..i, bounds inclusive.
int tmp = shuffleIndices[i];
shuffleIndices[i] = shuffleIndices[j] ;
shuffleIndices[j] = tmp ;
}
String[] shuffledStrings = new String[length];
double[] shuffledMeasures = new double[length];
for (int i=0 ; i<length ; i++) {
shuffledStrings[shuffleIndices[i]] = orderedStrings[i] ;
shuffledMeasures[shuffleIndices[i]] = orderedMeasures[i] ;
}
if (false && 0<length && length<8) {
System.out.println("shuffleIndices is "+ stringfor(shuffleIndices));
System.out.println("shuffledStrings is "+ stringfor(shuffledStrings));
System.out.println("shuffledMeasures is "+ stringfor(shuffledMeasures));
}
new NoDuplicatesTest(shuffledStrings, shuffledMeasures, orderedStrings);
}
}
}
private static class MultilengthMultiseedNoDuplicatesTest {
MultilengthMultiseedNoDuplicatesTest(int[] lengths, int[] seeds) {
for (int i=0 ; i<lengths.length ; i++) {
int length = lengths[i] ;
String[] orderedStrings = new String[length] ;
double[] orderedMeasures = new double[length] ;
for (int j=0 ; j<length ; j++) {
orderedStrings[j] = "_"+j+"_" ;
orderedMeasures[j] = j ;
}
if (false && 0<length && length<8) {
System.out.println("orderedStrings is "+ stringfor(orderedStrings));
System.out.println("orderedMeasures is "+ stringfor(orderedMeasures));
}
new MultiseedNoDuplicatesTest(orderedStrings, orderedMeasures, seeds);
}
}
}
public static class ClassTest {
ClassTest() {
new MultilengthMultiseedNoDuplicatesTest(new int[]{0}, new int[]{8543, 45125});
new MultilengthMultiseedNoDuplicatesTest(new int[]{1}, new int[]{8543, 45125});
new MultilengthMultiseedNoDuplicatesTest(new int[]{2}, new int[]{8543, 45125, 4545, 785413});
new MultilengthMultiseedNoDuplicatesTest(new int[]{3, 4, 5, 6, 7, 8, 9, 10}, new int[]{8543, 45125, 4545, 785413});
new MultilengthMultiseedNoDuplicatesTest(new int[]{50, 100, 1000}, new int[]{474854, 43233});
////// Passed! Bye bye.
System.out.println("Passed test suite "+this.getClass().getCanonicalName());
}
}
public static String stringfor(int[] array) {
StringBuilder sb = new StringBuilder();
build(sb, array);
return sb.toString();
}
public static void build(StringBuilder sb, int[] array) {
for (int i=0 ; i<array.length ; i++) {
if (sb.length()>0) sb.append(' ');
sb.append(array[i]);
}
}
public static String stringfor(double[] array) {
StringBuilder sb = new StringBuilder();
build(sb, array);
return sb.toString();
}
public static void build(StringBuilder sb, double[] array) {
for (int i=0 ; i<array.length ; i++) {
if (sb.length()>0) sb.append(' ');
sb.append(array[i]);
}
}
public static String stringfor(String[] labels) {
StringBuffer sb = new StringBuffer();
String sep = "" ;
for (int i=0 ; i<labels.length ; i++) {
sb.append(sep);
String label = labels[i] ;
sb.append(label!=null ? label : "null");
sep = ", " ;
}
return sb.toString();
}
}
回答by user1908375
Maybe not exactly for that case, but for those who looking for answer how to sort one array of String based on another:
也许不完全适用于这种情况,但对于那些寻找答案的人来说,如何根据另一个字符串对一个数组进行排序:
// Array of values, in a order of sorting
static final Map<String, Integer> ROUNDS_SORT = new HashMap<String, Integer>();
static {
ROUNDS_SORT.put("f", 0);
ROUNDS_SORT.put("s", 1);
ROUNDS_SORT.put("q", 2);
ROUNDS_SORT.put("r16", 3);
ROUNDS_SORT.put("r32", 4);
ROUNDS_SORT.put("r64", 5);
}
// Your array to be sorted
static ArrayList<String> rounds = new ArrayList<String>() {{
add("f");
add("q");
add("q");
add("r16");
add("f");
}};
// implement
public List<String> getRoundsSorted() {
Collections.sort(rounds, new Comparator<String>() {
@Override
public int compare(String p1, String p2) {
return Integer.valueOf(ROUNDS_SORT.get(p1)).compareTo(Integer.valueOf(ROUNDS_SORT.get(p2)));
}
});
return rounds;
}
回答by beee
In java you need to have two arrays one copy to sort off and the array you want to sort.
在 java 中,您需要有两个数组,一个副本要排序,另一个是要排序的数组。
with a lambda:
使用 lambda:
String[] strings = new String[]{"string1", "string2", "string3", "string4"};
final int[] ints = new int[]{100, 88, 92, 98};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
Or with Comparator:
或使用比较器:
String[] strings = new String[]{"string1", "string2", "string3", "string4"};
final int[] ints = new int[]{100, 92, 88, 98};
final List<String> stringListCopy = Arrays.asList(strings);
ArrayList<String> sortedList = new ArrayList(stringListCopy);
Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
回答by Arun Kumar
package com.appkart.array;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class SortExample {
Map<String, Integer> map = new HashMap<String, Integer>();
Map<String, Integer> treemap = new TreeMap<String, Integer>(
new MyComparator(map));
public void addValueInMapAndSort() {
map.put("string1", 40);
map.put("string2", 32);
map.put("string3", 34);
System.out.println(map);
treemap.putAll(map);
System.out.println(treemap);
}
class MyComparator implements Comparator<String> {
Map<String, Integer> map;
public MyComparator(Map<String, Integer> map) {
this.map = map;
}
@Override
public int compare(String o1, String o2) {
if (map.get(o1) >= map.get(o2)) {
return 1;
} else {
return -1;
}
}
}
public static void main(String[] args) {
SortExample example = new SortExample();
example.addValueInMapAndSort();
}
}
Use Comparator for sorting according to value.
使用 Comparator 根据值排序。
回答by simurg
If you're constructing array B only to be used for this sorting, you can defer calculating it's values within A's compareTo(). In other words, calculate weights of strings only in comparisons during sorting.
如果您构建的数组 B 仅用于此排序,您可以推迟在 A 的 compareTo() 中计算它的值。换句话说,仅在排序期间的比较中计算字符串的权重。
回答by The111
Make a TreeMap<Integer, List<ObjectTypeFromA>>
where the map key is the values in B, and the map values are the values in A (using a list to allow for duplicate keys). It will be sorted in the order of B by definition.
创建一个TreeMap<Integer, List<ObjectTypeFromA>>
,其中映射键是 B 中的值,映射值是 A 中的值(使用列表以允许重复键)。它将按照定义按 B 的顺序排序。
public static void main(String[] args) {
String[] strings = { "string1", "string2", "string3", "string4" };
int[] ints = { 40, 32, 32, 34 };
System.out.println(Arrays.toString(getSortedStringArray(strings, ints)));
}
public static String[] getSortedStringArray(String[] strings, int[] order) {
Map<Integer, List<String>> map = new TreeMap<>();
for (int i = 0; i < strings.length; i++) {
if (!map.containsKey(order[i])) {
map.put(order[i], new LinkedList<String>());
}
map.get(order[i]).add(strings[i]);
}
String[] ret = new String[strings.length];
int i = 0;
for (Map.Entry<Integer, List<String>> mapEntry : map.entrySet()) {
for (String s : mapEntry.getValue()) {
ret[i++] = s;
}
}
return ret;
}