2

私はPythonでプロトタイプを作成し、これにzip関数を使用していますが、Javaでこれを行う方法がわかりません。基本的に私は2つのリスト(1つはとnames1つはdata)を持っており、それらを相互に関連してソートしたいと思っています。私のプログラムはリスト(dataこの場合は)のみを処理しますが、処理namesしているものへの参照としてを使用dataし、別の順序でデータを処理して実験したいと思います。構造の例を次に示します(実際には、データは保存された状態で提供されませんが、基本的な並べ替えまたは逆の並べ替えを行いますが、特別なことは何もありません)。

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

私はこの質問を見つけました:Pythonのzip()に相当する受け入れられたJavaはありますが、私はむしろ(可能であればそして気の弱い人のために)私がすでに持っているライブラリ(Javaコモン、apacheコモンなど)を使用してこれを行います。他に方法がない場合は、私がfunctional javaショットを与えます。助言がありますか?

4

7 に答える 7

7

データ構造をやり直して情報を結合したくない場合は、マルチマップを使用してそれを行うことができます。

この例では、とにかく使用する必要がある優れた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);
    }
}
于 2012-05-01T13:28:58.607 に答える
6

完全なコードは次のとおりです。

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フィールドでソートされ、次にStringフィールドでソートされます):

[(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;
    }

}
于 2012-04-18T16:33:13.250 に答える
2

Javaでこれを行う「正しい」方法は、対応する要素を保持する結合オブジェクトを作成し、それをソートすることです。

例:

class NameAndData {
  private final String name;
  private final int data;
}

List<NameAndData> toBeSorted;

次に、結合された要素のリストを作成し、それを並べ替えます。基本的に、あなたはあなた自身の特定のPairクラスを書いています。(私と多くのJava開発者は、PairJavaにクラスを追加すると、コードがより難読化されると考えています。LatLongたとえば、クラスは、それが何を意味するかについて、より曖昧ではありませんPair<Double, Double>。)

于 2012-04-18T16:12:41.950 に答える
2

したがって、ここでの明白な答えは、nameとのdata値をクラスでラップすることです。次に、そのクラスのリストを維持します。クラスはを実装する必要があります。これによりequals、を使用してリストを並べ替えることができます。hashCodeComparableCollections.sort

2つの異なるリストで関連データを維持することは反OOPです。

このようなもの。

class MyWrapper implements Comparable<MyWrapper>{
   private String name;
   private int data;
}

List<MyWrapper> listToBeSorted;
于 2012-04-18T16:14:54.287 に答える
2

場合によっては、並行ソートを実行するためだけに新しいクラスを作成してもあまり意味がありません。

Listここでは、実装するキーに基づいて、任意の数のsを任意の型でソートするために使用できる関数です(ここではComparableIdeoneの例)。


使用法

この関数を使用して、任意のタイプの複数のリストを並べ替える方法の例を次に示します。

// 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の例がここにあります。

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));
}
于 2014-07-11T01:01:29.397 に答える
1

ConcurrentSkipListMapキーに対して順方向および逆方向のイテレータを提供できるを使用できます。固定の順方向および逆方向の順序以外に任意の再順序を探している場合は、別の場所に移動する必要があります。HashMapまたは、並列アイテムの関連付けを維持するために、いつでも単純なものを維持し、必要に応じて適切なを提供することでSortedMapTreemapまたは)を作成できます。ConcurrentSkipListMapComparator

このアプローチの欠点は、キー/値間の関連付けがはるかに一時的であり、マップの更新によって簡単かつ偶発的に壊れてしまう可能性があることです。タプル、ペア、またはその他の明示的な1-1関係を作成する他のすべての回答は、それをより適切に処理します。もちろん、関連付けをより流動的にする場合は、マップを使用するだけで少し利点があります。

于 2012-04-18T16:26:41.287 に答える
1

これら2つの配列の長さが同じであると仮定すると、これらの配列の要素のペアを含むマップエントリのリストを作成し、次のようにこのリストをキーの逆順に並べ替えることができます。

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]

参照:2つの並列配列のソート

于 2021-02-01T00:16:27.200 に答える