我在python中进行原型设计并且我使用了zip函数,我不知道如何在Java中执行此操作。基本上我有两个列表(一个是名称,一个是数据),并希望它们相互排序。我的程序只处理一个列表(数据,在这种情况下),但我使用名称作为我正在处理的数据的参考,我想尝试以不同的顺序处理我的数据。这是一个结构的例子(实际上我的数据不是存储给我的,但我会对它进行基本排序或反向排序,没什么特别的。)
String[] names = new String[] {"Monkey1", "Dog2", "Horse3", "Cow4", "Spider5"};
int[] data = new int[] {1,2,3,4,5};
所以反过来就是
name = Spider5, Cow4, Horse3, Dog2, Monkey1
data = 5,4,3,2,1
我发现了这个问题:Is there an accepted Java equivalent to Python's zip()?但我宁愿(如果可能的话,对于胆小的人)使用我已经拥有的库(Java commons,apache commons等)来做这件事。如果没有别的办法,我会给functional java
一个机会。有什么建议吗?
答案 0 :(得分:5)
如果您真的不想重做数据结构来组合信息,可以使用Multimap来完成。
这个例子使用了优秀的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);
}
}
答案 1 :(得分:4)
这是完整的代码:
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:
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:
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:
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());
}
}
输出(首先按int字段排序,然后按字符串字段排序):
[(1,Monkey1),(2,Dog2),(3,Horse3),(4,Cow4),(5,Spider5)]
[(4,Cow4),(2,Dog2),(3,Horse3),(1,Monkey1),(5,Spider5)]
编辑1(额外信息):
如果你想让任何元组工作,即不将字段类型约束为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;
}
然后,只需相应调整比较器,您就拥有了通用的解决方案。 编辑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);
}
}
编辑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;
}
}
答案 2 :(得分:2)
在Java中执行此操作的“正确”方法是创建一个组合对象,该对象包含相应的元素,并对其进行排序。
示例:
class NameAndData {
private final String name;
private final int data;
}
List<NameAndData> toBeSorted;
然后创建组合元素的列表并对其进行排序。基本上,您正在编写自己的特定Pair
课程。 (我和许多Java开发人员认为向Java添加Pair
类只会导致更多的模糊代码 - 例如,LatLong
类对于它的含义要比对它的含义要小得多。 Pair<Double, Double>
。)
答案 3 :(得分:2)
所以这里显而易见的答案是将name
和data
值包装在一个类中。然后维护该类的List。该类应实现equals
,hashCode
和Comparable
,然后允许使用Collections.sort
对列表进行排序。
维护两个不同列表中的相关数据是反OOP。
像这样。
class MyWrapper implements Comparable<MyWrapper>{
private String name;
private int data;
}
List<MyWrapper> listToBeSorted;
答案 4 :(得分:1)
您可以使用ConcurrentSkipListMap
,它可以通过键提供正向和反向迭代器。如果您正在寻找除固定正向和反向订购之外的任意重新排序,您将不得不去做其他事情。或者,您始终可以保留一个简单的HashMap
或其他任何内容来维护并行项关联,然后根据需要构建SortedMap
(Treemap
或ConcurrentSkipListMap
),提供适当的{{ 1}}。
这种方法的缺点是键/值之间的关联更加短暂,并且可以通过更新地图更容易和意外地破坏。创建元组,对或其他明确的1-1关系的所有其他答案都能更好地解决这个问题。当然,如果你打算让关联变得更加流畅,那么只需使用地图就会增加一些优势。
答案 5 :(得分:1)
在某些情况下,创建一个新类只是为了进行并发排序没有多大意义。
此处是一个函数,可用于根据实现List
(Ideone Example here)的键对任意类型的Comparable
进行排序。
以下是如何使用该函数对任意类型的多个列表进行排序的示例:
// 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);
输出
key: [1, 1, 2, 3, 4]
list1: [One, One, Two, Three, Four]
list2: [a, a, b, c, d]
可以找到Ideone示例here,其中包括参数验证和测试用例。
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));
}
答案 6 :(得分:1)
假设这两个数组的长度相同,您可以创建一个映射条目列表,其中包含来自这些数组的元素对,并按键对该列表进行相反的排序 如下:
String[] names = new String[]{"Monkey1", "Dog2", "Horse3", "Cow4", "Spider5"};
int[] data = new int[]{1, 2, 3, 4, 5};
List<Map.Entry<Integer, String>> entryList = IntStream
.range(0, names.length)
.mapToObj(i -> Map.entry(data[i], names[i]))
.sorted(Map.Entry.<Integer, String>comparingByKey().reversed())
.collect(Collectors.toList());
System.out.println(entryList);
// [5=Spider5, 4=Cow4, 3=Horse3, 2=Dog2, 1=Monkey1]
如果要替换数组的内容:
IntStream.range(0, entryList.size()).forEach(i -> {
data[i] = entryList.get(i).getKey();
names[i] = entryList.get(i).getValue();
});
System.out.println(Arrays.toString(data));
// [5, 4, 3, 2, 1]
System.out.println(Arrays.toString(names));
// [Spider5, Cow4, Horse3, Dog2, Monkey1]