java 我可以对两个相互关联的列表进行排序吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10213493/
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
Can I sort two lists in relation to each other?
提问by Error_404
I prototype in python and I'm used the zip function for this, I'm not sure how to do this in Java. Basically I have two lists(one is names and one is data) and want them sorted in relation to each other. My program only processes a list(data, in this case) but I use the names as a reference to what data I'm processing and I want to try to experiment with processing my data in a different order. Here's an example of the structure(in reality my data is not given to me stored but I would do either a basic sort or a reverse sort on it, nothing fancy).
我在 python 中创建原型,我为此使用了 zip 函数,我不确定如何在 Java 中执行此操作。基本上我有两个列表(一个是名称,一个是数据)并希望它们相互排序。我的程序只处理一个列表(在这种情况下是数据),但我使用名称作为我正在处理的数据的参考,我想尝试以不同的顺序处理我的数据。这是结构的一个例子(实际上我的数据并没有提供给我存储,但我会对其进行基本排序或反向排序,没什么特别的)。
String[] names = new String[] {"Monkey1", "Dog2", "Horse3", "Cow4", "Spider5"};
int[] data = new int[] {1,2,3,4,5};
so the inverse would be
所以逆将是
name = Spider5, Cow4, Horse3, Dog2, Monkey1
data = 5,4,3,2,1
I found this question: Is there an accepted Java equivalent to Python's zip()?but I would rather(if possible and for the faint of heart) do this using libraries I already have(Java commons, apache commons,etc). If there's no other way then I'll give functional java
a shot. Any suggestions?
我发现了这个问题:是否存在与 Python 的 zip() 等效的公认 Java?但我更愿意(如果可能的话,胆小的人)使用我已经拥有的库(Java commons、apache commons 等)来做这件事。如果没有其他办法,那我就functional java
试一试。有什么建议?
回答by Fabian Zeindl
If you really don't want to redo your data-structures to combine the infos, you can use a Multimap to do it.
如果你真的不想重做你的数据结构来组合信息,你可以使用 Multimap 来做到这一点。
This example utilizes the excellent Google-Guava Library, which you should be using anyway :) https://code.google.com/p/guava-libraries/
此示例利用了出色的 Google-Guava 库,无论如何您都应该使用它:) https://code.google.com/p/guava-libraries/
String[] names = new String[] {"Monkey1", "Dog2", "Horse3", "Cow4", "Spider5"};
int[] data = new int[] {1,2,3,4,5};
/* guava, throws an IllegalStateException if your array aren't of the same length */
Preconditions.checkState(names.length == data.length, "data and names must be of equal length");
/* put your values in a MultiMap */
Multimap<String, Integer> multiMap = LinkedListMultimap.create();
for (int i=0; i<names.length; i++) {
mmap.put(names[i], data[i]);
}
/* our output, 'newArrayList()' is just a guava convenience function */
List<String> sortedNames = Lists.newArrayList();
List<Integer> sortedData = Lists.newArrayList();
/* cycle through a sorted copy of the MultiMap's keys... */
for (String name : Ordering.natural().sortedCopy(mmap.keys())) {
/* ...and add all of the associated values to the lists */
for (Integer value : mmap.get(name)) {
sortedNames.add(name);
sortedData.add(value);
}
}
回答by Greg Kramida
Here's complete code:
这是完整的代码:
StringIntTuple.java:
StringIntTuple.java:
public class StringIntTuple{
public final int intValue;
public final String stringValue;
public StringIntTuple(int intValue, String stringValue){
this.intValue = intValue;
this.stringValue = stringValue;
}
public String toString(){
return "(" + this.intValue + ", " + this.stringValue + ")";
}
}
StringIntTupleStringComparator.java:
StringIntTupleStringComparator.java:
import java.util.Comparator;
public class StringIntTupleStringComparator implements
Comparator<StringIntTuple> {
@Override
public int compare(StringIntTuple a, StringIntTuple b) {
// TODO Auto-generated method stub
return a.stringValue.compareTo(b.stringValue);
}
}
StringIntTupleIntComparator.java:
StringIntTupleIntComparator.java:
import java.util.Comparator;
public class StringIntTupleIntComparator implements Comparator<StringIntTuple> {
@Override
public int compare(StringIntTuple a,
StringIntTuple b) {
return ((Integer)a.intValue).compareTo((Integer)b.intValue);
}
}
Driver.java:
驱动程序.java:
import java.util.ArrayList;
import java.util.Collections;
public class Driver {
/**
* @param args
*/
public static String[] names = new String[] {"Monkey1", "Dog2", "Horse3", "Cow4", "Spider5"};
public static int[] data = new int[] {1,2,3,4,5};
public static void main(String[] args) {
ArrayList<StringIntTuple> list = new ArrayList<StringIntTuple>();
for(int i =0; i<names.length; i++){
list.add(new StringIntTuple(data[i],names[i]));
}
Collections.sort(list, new StringIntTupleIntComparator());
System.out.println(list.toString());
Collections.sort(list, new StringIntTupleStringComparator());
System.out.println(list.toString());
}
}
Output (sorted first by int field, then by String field):
输出(首先按 int 字段排序,然后按 String 字段排序):
[(1, Monkey1), (2, Dog2), (3, Horse3), (4, Cow4), (5, Spider5)]
[(1, Monkey1), (2, Dog2), (3, Horse3), (4, Cow4), (5, Spider5)]
[(4, Cow4), (2, Dog2), (3, Horse3), (1, Monkey1), (5, Spider5)]
[(4, Cow4), (2, Dog2), (3, Horse3), (1, Monkey1), (5, Spider5)]
EDIT 1 (extra info):
编辑 1(额外信息):
If you want to make this work for any Tuple, i.e. which doesn't constrain the field types to int, String, you can simply do the same operation with generics, i.e.:
如果您想对任何元组(即不将字段类型限制为 int、String)进行此操作,您可以简单地对泛型执行相同的操作,即:
public class Tuple<A,B>{
public Tuple(A aValue, B bValue){
this.aValue = aValue;
this.bValue = bValue;
}
public final A aValue;
public final B bValue;
}
Then, just tweak the Comparators accordingly, and you have a generic solution. EDIT 2(After lunch): Here it is.
然后,只需相应地调整比较器,您就有了一个通用的解决方案。编辑 2(午餐后):就是这样。
public class TupleAComparator<A extends Comparable<A>,B extends Comparable<B>> implements Comparator<Tuple<A,B>> {
@Override
public int compare(Tuple<A, B> t1, Tuple<A, B> t2) {
return t1.aValue.compareTo(t2.aValue);
}
}
EDIT 3: Code supplement as answer to Comment #1 (augmenting comment #2) TupleArrayList.java:
编辑 3:代码补充作为评论 #1(增加评论 #2)TupleArrayList.java 的答案:
import java.util.ArrayList;
import java.util.List;
public class TupleArrayList<A,B> extends ArrayList<Tuple<A,B>> {
/**
* An ArrayList for tuples that can generate a List of tuples' elements from a specific position within each tuple
*/
private static final long serialVersionUID = -6931669375802967253L;
public List<A> GetAValues(){
ArrayList<A> aArr = new ArrayList<A>(this.size());
for(Tuple<A,B> tuple : this){
aArr.add(tuple.aValue);
}
return aArr;
}
public List<B> GetBValues(){
ArrayList<B> bArr = new ArrayList<B>(this.size());
for(Tuple<A,B> tuple : this){
bArr.add(tuple.bValue);
}
return bArr;
}
}
回答by Louis Wasserman
The "right" way to do this in Java is to create a combined object that holds the corresponding elements, and to sort that.
在 Java 中执行此操作的“正确”方法是创建一个包含相应元素的组合对象,然后对其进行排序。
Example:
例子:
class NameAndData {
private final String name;
private final int data;
}
List<NameAndData> toBeSorted;
and then you create a list of the combined elements and sort that. Basically, you're writing your own specific Pair
class. (I, and many Java developers, think that adding a Pair
class to Java would just lead to more obfuscated code -- a LatLong
class, for example, is much less ambiguous about what it means than a Pair<Double, Double>
.)
然后创建一个组合元素列表并对其进行排序。基本上,您正在编写自己的特定Pair
类。(我和许多 Java 开发人员都认为,向Pair
Java添加一个类只会导致代码更加混乱——LatLong
例如,一个类的含义比Pair<Double, Double>
.更明确。)
回答by John B
So the obvious answer here is to wrap the name
and data
values in a class. Then maintain a List of that class. The class should implement equals
, hashCode
and Comparable
which then then allow sorting the list using Collections.sort
.
所以这里显而易见的答案是将name
和data
值包装在一个类中。然后维护一个该类的列表。类应该实现equals
,hashCode
并且Comparable
然后再允许使用排序列表Collections.sort
。
Maintain related data in two different lists is anti-OOP.
在两个不同的列表中维护相关数据是反 OOP 的。
Something like this.
像这样的东西。
class MyWrapper implements Comparable<MyWrapper>{
private String name;
private int data;
}
List<MyWrapper> listToBeSorted;
回答by Kevin Welker
You could use a ConcurrentSkipListMap
which can provide forward and reverse iterators over the keys. If you are looking for arbitrary re-orderings besides a fixed forward and reverse ordering, you'll have to go to something else. Or you can always keep a simple HashMap
or whatever to maintain parallel item associations, and then construct a SortedMap
(Treemap
or ConcurrentSkipListMap
) as needed by providing an appropriate Comparator
.
您可以使用ConcurrentSkipListMap
可以在键上提供正向和反向迭代器的 a 。如果您正在寻找除固定的正向和反向排序之外的任意重新排序,则您将不得不进行其他操作。或者,您可以始终保持一个简单的HashMap
或任何保持平行项关联,然后构造一个SortedMap
(Treemap
或ConcurrentSkipListMap
根据需要通过提供适当的)Comparator
。
The disadvantage of this approach is that the associations between keys/values are much more transient, and can be more easily and accidentally broken by updates to the map. All of the other answers that create Tuples, Pairs, or other explicit 1-1 relationships address that better. Of course, if you intend for the associations to be more fluid, then just using a map adds a bit of an advantage.
这种方法的缺点是键/值之间的关联更加短暂,并且更容易被更新映射而意外破坏。创建元组、对或其他明确的 1-1 关系的所有其他答案都更好地解决了这个问题。当然,如果您希望关联更加流畅,那么仅使用地图会增加一些优势。
回答by bcorso
In some cases it doesn't make much sense to create a new class just to do concurrent sorting.
在某些情况下,创建一个新类只是为了进行并发排序并没有多大意义。
Here, is a function that can be used to sort an arbitrary number of List
s with arbitrary types based on a key that implement Comparable
(Ideone Example here).
这是一个函数,可用于List
根据实现的键Comparable
(此处为 Ideone 示例)对任意数量的任意类型的s进行排序。
Usage
用法
Here is an example of how you can use the function to sort multiple lists of arbitrary types:
下面是一个示例,说明如何使用该函数对多个任意类型的列表进行排序:
// Can be any type that implements Comparable, Dupes are allowed
List<Integer> key = Arrays.asList(4, 3, 1, 2, 1);
// List Types do not need to be the same
List<String> list1 = Arrays.asList("Four", "Three", "One", "Two", "One");
List<Character> list2 = Arrays.asList('d', 'c', 'a', 'b', 'a');
// Sorts key, list1, list2
// Remove second key if you don't want to sort key.
multiSort(key, key, list1, list2);
Output:
输出:
key: [1, 1, 2, 3, 4]
list1: [One, One, Two, Three, Four]
list2: [a, a, b, c, d]
Code
代码
An Ideone Example can be found herewhich includes validation of parameters and a test case.
可以在此处找到 Ideone 示例,其中包括参数验证和测试用例。
public static <T extends Comparable<T>> void multiSort(
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));
}