私は次の3つの配列を持っています:
int[] indexes = new int[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
インデックスに基づいて3つの配列を並べ替えたいと思います。
indexes -> {0,2,5,8}
sources -> {"how", "are", "you", "today"}
targets -> {"I", "am", "fine", "thanks"}
3つの要素すべてを使用して新しいクラスmyClass
を作成できます。
class myClass {
int x;
String source;
String target;
}
すべてをmyClassに再割り当てし、myClass
を使用してx
を並べ替えます。ただし、これには追加のスペースが必要になります。 in place
ソートを実行できるかどうか疑問に思っていますか?ありがとう!
これを行う3つの方法
1。コンパレータの使用(Need Java 8 plus)
import Java.io.*;
import Java.util.*;
class Test {
public static String[] sortWithIndex (String[] strArr, int[] intIndex )
{
if (! isSorted(intIndex)){
final List<String> stringList = Arrays.asList(strArr);
Collections.sort(stringList, Comparator.comparing(s -> intIndex[stringList.indexOf(s)]));
return stringList.toArray(new String[stringList.size()]);
}
else
return strArr;
}
public static boolean isSorted(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] < arr[i]) {
return false;
};
}
return true;
}
// Driver program to test function.
public static void main(String args[])
{
int[] indexes = new int[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
String[] sortedSources = sortWithIndex(sources,indexes);
String[] sortedTargets = sortWithIndex(targets,indexes);
Arrays.sort(indexes);
System.out.println("Sorted Sources " + Arrays.toString(sortedSources) + " Sorted Targets " + Arrays.toString(sortedTargets) + " Sorted Indexes " + Arrays.toString(indexes));
}
}
出力
Sorted Sources [how, are, you, today] Sorted Targets [I, am, fine, thanks] Sorted Indexes [0, 2, 5, 8]
2。Lambdaの使用(Need Java 8 plus)
import Java.io.*;
import Java.util.*;
public class Test {
public static String[] sortWithIndex (String[] strArr, int[] intIndex )
{
if (! isSorted(intIndex)) {
final List<String> stringList = Arrays.asList(strArr);
Collections.sort(stringList, (left, right) -> intIndex[stringList.indexOf(left)] - intIndex[stringList.indexOf(right)]);
return stringList.toArray(new String[stringList.size()]);
}
else
return strArr;
}
public static boolean isSorted(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] < arr[i]) {
return false;
};
}
return true;
}
// Driver program to test function.
public static void main(String args[])
{
int[] indexes = new int[]{0,2,5,8};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
String[] sortedSources = sortWithIndex(sources,indexes);
String[] sortedTargets = sortWithIndex(targets,indexes);
Arrays.sort(indexes);
System.out.println("Sorted Sources " + Arrays.toString(sortedSources) + " Sorted Targets " + Arrays.toString(sortedTargets) + " Sorted Indexes " + Arrays.toString(indexes));
}
}
。リストとマップを使用し、個々の配列を並べ替えるメソッドへの複数の呼び出しを回避する(上記の2番目のソリューションのように)
import Java.util.*;
import Java.lang.*;
import Java.io.*;
public class Test{
public static <T extends Comparable<T>> void sortWithIndex( final List<T> key, List<?>... lists){
// input validation
if(key == null || lists == null)
throw new NullPointerException("Key cannot be null.");
for(List<?> list : lists)
if(list.size() != key.size())
throw new IllegalArgumentException("All lists should be of the same size");
// Lists are size 0 or 1, nothing to sort
if(key.size() < 2)
return;
// 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));
}
});
Map<Integer, Integer> swapMap = new HashMap<Integer, Integer>(indices.size());
List<Integer> swapFrom = new ArrayList<Integer>(indices.size()),
swapTo = new ArrayList<Integer>(indices.size());
// create a mapping that allows sorting of the List by N swaps.
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));
}
public static void main (String[] args) throws Java.lang.Exception{
List<Integer> index = Arrays.asList(0,2,8,5);
List<String> sources = Arrays.asList("how", "are", "today", "you");
// List Types do not need to be the same
List<String> targets = Arrays.asList("I", "am", "thanks", "fine");
sortWithIndex(index, index, sources, targets);
System.out.println("Sorted Sources " + sources + " Sorted Targets " + targets + " Sorted Indexes " + index);
}
}
出力
Sorted Sources [how, are, you, today] Sorted Targets [I, am, fine, thanks] Sorted Indexes [0, 2, 5, 8]
見た目ほど簡単ではありませんが、可能です。 2つのオプションがあります:
独自のソートアルゴリズムを記述してくださいここで、2つの要素のスワップ関数は、他の配列の要素もスワップします。
AFAIKは、追加の配列を交換する方法で標準_Array.sort
_を拡張する方法はありません。
ソート順でヘルパー配列を使用します。
まず、ヘルパー配列を範囲_{0, 1 ... indexes.Length-1}
_で初期化する必要があります。
ここで、ヘルパー配列を並べ替えるComparator
をa
ではなく_indexes[a]
_と_indexes[b]
_を比較するb
を使用します。結果はヘルパー配列であり、各要素には、そのコンテンツが由来するソース配列の要素のインデックス、つまりソートシーケンスがあります。
最後のステップは最もトリッキーなものです。 上記の並べ替え順序に従ってソース配列の要素を交換する必要があります。
操作するには厳密に配置現在のインデックスcur
を_0
_に設定します。
次に、ヘルパー配列からcur
番目の要素を取得します。それをfrom
と呼びましょう。これは、完了後にインデックスcur
に配置する必要がある要素インデックスです。
ここで、インデックスcur
の要素を配置するために、インデックスfrom
にスペースを作成する必要があります。それらを一時的な場所tmp
にコピーします。
次に、要素をインデックスfrom
からインデックスcur
に移動します。インデックスfrom
は自由に上書きできるようになりました。
インデックスcur
のヘルパー配列の要素を無効な値に設定します。例: _-1
_。
現在のインデックスcur
をfrom
に設定します。ヘルパー配列内の、すでに無効なインデックス値を持つ要素、つまり開始点に到達するまで、上から続行します。この場合、tmp
の内容を最後のインデックスに保存します。これで、回転したインデックスの閉ループが見つかりました。
残念ながら、それぞれが任意のサイズのループが任意の数存在する可能性があります。したがって、ヘルパー配列で次の無効でないインデックス値を探し、ヘルパー配列のすべての要素が処理されるまで上から続行する必要があります。各ループの後に開始点で終了するため、無効でないエントリが見つからない限り、cur
をインクリメントするだけで十分です。したがって、ヘルパー配列の処理中、アルゴリズムはまだO(n)です。cur
より前のすべてのエントリは、ループが完了した後は必ず無効になります。
ヘルパー配列のサイズを超えてcur
がインクリメントされた場合は完了です。
新しいターゲット配列を作成できる場合は、オプション2のバリエーションが簡単になります。
この場合、新しいターゲット配列を割り当て、ヘルパー配列のインデックスに従ってそれらのコンテンツを入力するだけです。
欠点は、配列が非常に大きい場合、割り当てにかなりの費用がかかる可能性があることです。そしてもちろん、それはもはやインプレースではありません。
いくつかの追加の注意事項。
通常、カスタムソートアルゴリズムは、一時配列の割り当てを回避するため、パフォーマンスが向上します。しかし、場合によっては状況が変わります。循環要素回転ループの処理では、最小移動操作を使用します。これは、一般的な並べ替えアルゴリズムのO(n log n)ではなくO(n)です。したがって、並べ替える配列の数や配列のサイズが大きくなると、メソッド#2にはスワップ操作の使用量が少ないため、利点があります。
このようなソートアルゴリズムを必要とするデータモデルは、ほとんどの場合設計上壊れています。もちろん、いつものように、これを避けられない場合がいくつかあります。
整数をキーとして使用して、TreeMap
などを使用することをお勧めします。
static Map<Integer, myClass> map = new TreeMap<>();
したがって、順序付きを取得する場合は、forループまたは任意の操作を実行するだけで済みます。
for (int i : map.keyset()){
System.out.println("x: "+map.get(i).x+"\nsource: "+map.get(i).source+"\ntarget: "+map.get(i).target);
}
この例では、インデックスの整数配列を作成する必要がありますが、並べ替える配列はarray1に従って所定の位置に並べ替えられ、配列はインデックスを作成できる任意のタイプ(プリミティブまたはオブジェクト)にすることができます。
public static void main(String[] args) {
int array1[]={5,1,9,3,8};
int array2[]={2,0,3,6,1};
int array3[]={3,1,4,5,9};
// generate array of indices
Integer[] I = new Integer [array1.length];
for(int i = 0; i < I.length; i++)
I[i] = i;
// sort array of indices according to array1
Arrays.sort(I, (i, j) -> array1[i]-array1[j]);
// reorder array1 ... array3 in place using sorted indices
// also reorder indices back to 0 to length-1
// time complexity is O(n)
for(int i = 0; i < I.length; i++){
if(i != I[i]){
int t1 = array1[i];
int t2 = array2[i];
int t3 = array3[i];
int j;
int k = i;
while(i != (j = I[k])){
array1[k] = array1[j];
array2[k] = array2[j];
array3[k] = array3[j];
I[k] = k;
k = j;
}
array1[k] = t1;
array2[k] = t2;
array3[k] = t3;
I[k] = k;
}
}
// display result
for (int i = 0; i < array1.length; i++) {
System.out.println("array1 " + array1[i] +
" array2 " + array2[i] +
" array3 " + array3[i]);
}
}
Collection
を使用する別の解決策(メモリ使用量を増やす):
ソートされたマップを作成して、正しいインデックスと元の位置の間のマッピングにしましょう。
public static TreeMap<Integer, Integer> sortIndex(int[] array){
TreeMap<Integer, Integer> tree = new TreeMap<>();
for(int i=0; i < array.length; ++i) {
tree.put(array[i], i);
}
return tree;
}
テスト:
int[] indexes = new int[] { 0, 1, 3, 2, 4, 5 };
TreeMap<Integer, Integer> map = sortIndex(indexes);
map.keySet().stream().forEach(System.out::print); //012345
map.values().stream().forEach(System.out::print); //013245
インデックスは(キー上で)ソートされ、元のインデックスの順序が値として使用されます。
いいえ、これを使用して配列を簡単に注文することはできません。思い切ってStream
を使用して、List
にマップして収集します。
public static List<String> sortInPlace(String[] array, TreeMap<Integer, Integer> map) {
return map.values().stream().map(i -> array[i]).collect(Collectors.toList());
}
テスト:
String[] sources = "to be not or to be".split(" ");
int[] indexes = new int[] { 0, 1, 3, 2, 4, 5 };
TreeMap<Integer, Integer> map = sortIndex(indexes);
List<String> result = sortInPlace(sources, map);
System.out.println(result);
[to、be、or、not、to、be]
なぜ私はList
を使用したのですか。主に再注文を簡素化するために、元の配列を注文しようとすると、反対側のキー/ペアを削除する必要があるため、複雑になります
2 -> 3
3 -> 2
クリーニングを行わずに、セルを2回交換するだけなので、変更はありません。
メモリ使用量を少し減らしたい場合は、ストリームを使用する代わりに別の配列を作成し、マップを反復する値ごとに値をコピーできます。これは、複数のアレイを並列に使用する場合にも可能です。
私のアプローチは有効かどうか疑問に思います。
public class rakesh{
public static void sort_myClass(myClass myClasses[]){
for(int i=0; i<myClasses.length; i++){
for(int j=0; j<myClasses.length-i-1; j++){
if(myClasses[j].x >myClasses[j+1].x){
myClass temp_myClass = new myClass(myClasses[j+1]);
myClasses[j+1] = new myClass(myClasses[j]);
myClasses[j] = new myClass(temp_myClass);
}
}
}
}
public static class myClass{
int x;
String source;
String target;
myClass(int x,String source,String target){
this.x = x;
this.source = source;
this.target = target;
}
myClass(myClass super_myClass){
this.x = super_myClass.x;
this.source = super_myClass.source;
this.target = super_myClass.target;
}
}
public static void main(String args[]) {
myClass myClass1 = new myClass(0,"how","I");
myClass myClass2 = new myClass(2,"are","am");
myClass myClass3 = new myClass(8,"today","thanks");
myClass myClass4 = new myClass(5,"you","fine");
myClass[] myClasses = {myClass1, myClass2, myClass3, myClass4};
sort_myClass(myClasses);
for(myClass myClass_dummy : myClasses){
System.out.print(myClass_dummy.x + " ");
}
System.out.print("\n");
for(myClass myClass_dummy : myClasses){
System.out.print(myClass_dummy.source + " ");
}
System.out.print("\n");
for(myClass myClass_dummy : myClasses){
System.out.print(myClass_dummy.target + " ");
}
}
}
エラーを見つけたり、提案がある場合は、コメントを残してください。必要な編集を行うことができます。
出力
0 2 5 8
今日は元気ですか
元気ですありがとう
プロセスは終了コード0で終了しました
クラスに値を割り当てなくても、次のコードでそれを実現できます。
Integer[] indexes = new Integer[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
Integer[] sortedArrya = Arrays.copyOf(indexes, indexes.length);
Arrays.sort(sortedArrya);
String[] sortedSourses = new String[sources.length];
String[] sortedTargets = new String[targets.length];
for (int i = 0; i < sortedArrya.length; i++) {
int intValus = sortedArrya[i];
int inx = Arrays.asList(indexes).indexOf(intValus);
sortedSourses[i] = sources[+inx];
sortedTargets[i] = targets[+inx];
}
System.out.println(sortedArrya);
System.out.println(sortedSourses);
System.out.println(sortedTargets);
それはすべてあなたの配列のサイズに依存します。このソリューションでは、最初の配列を使用して並べ替えを実行しますが、複数の配列で順列を実行します。
したがって、使用されるソートアルゴリズムで多くの順列が必要になる場合、これにはパフォーマンスの問題が発生する可能性があります。
ここでは、2つのセルの交換中に実行できるいくつかのアクションを追加した、基本的な並べ替えアルゴリズムを採用しました。これにより、ラムダを定義して、1つの配列に基づいて複数の配列を同時にスワップすることができます。
public static void sortArray( int[] array, BiConsumer<Integer, Integer>... actions ) {
int tmp;
for ( int i = 0, length = array.length; i < length; ++i ) {
tmp = array[i];
for ( int j = i + 1; j < length; ++j ) {
if ( tmp > array[j] ) {
array[i] = array[j];
array[j] = tmp;
tmp = array[i];
// Swap the other arrays
for ( BiConsumer<Integer, Integer> cons : actions ){
cons.accept( i, j);
}
}
}
}
}
BiConsumer
ラムダとして渡すことができるセルを交換するための汎用メソッドを作成しましょう(非プリミティブ配列でのみ機能します)。
public static <T> void swapCell( T[] array, int from, int to ) {
T tmp = array[from];
array[from] = array[to];
array[to] = tmp;
}
これにより、次のように配列を並べ替えることができます。
public static void main( String[] args ) throws ParseException {
int[] indexes = new int[] { 0, 2, 8, 5 };
String[] sources = new String[] { "how", "are", "today", "you" };
String[] targets = new String[] { "I", "am", "thanks", "fine" };
sortArray( indexes,
( i, j ) -> swapCell( sources, i, j ),
( i, j ) -> swapCell( targets, i, j ) );
System.out.println( Arrays.toString( indexes ) );
System.out.println( Arrays.toString( sources ) );
System.out.println( Arrays.toString( targets ) );
}
[0、2、5、8]
[今日は元気ですか]
[私、元気です、ありがとう]
このソリューションでは、追加の配列やCollection
が必要ないため、すでに使用されているものよりも(はるかに)多くのメモリは必要ありません。
BiConsumer<>...
を使用すると、一般的なソリューションが提供されます。これはObject[]...
も受け入れることができますが、プリミティブ配列では機能しなくなります。もちろん、これはわずかなパフォーマンスの低下があるため、必要に応じて削除できます。
完全なソリューションの作成では、最初に、ファクトリとしても使用されるインターフェイスを定義しましょう。
interface Sorter {
void sort(int[] array, BiConsumer<Integer, Integer>... actions);
static void sortArrays(int[] array, BiConsumer<Integer, Integer>... actions){
// call the implemented Sorter
}
}
次に、前と同じロジックで単純な選択ソーターを実装します。元の配列の順列ごとに、BiConsumer
を実行します。
class SelectionSorter implements Sorter {
public void sort(int[] array, BiConsumer<Integer, Integer>... actions) {
int index;
int value;
int tmp;
for (int i = 0, length = array.length; i < length; ++i) {
index = i;
value = array[i];
for (int j = i + 1; j < length; ++j) {
if (value > array[j]) {
index = j;
value = array[j];
}
}
if (index != i) {
tmp = array[i];
array[i] = array[index];
array[index] = tmp;
// Swap the other arrays
for (BiConsumer<Integer, Integer> cons : actions) {
cons.accept(i, index);
}
}
}
}
}
バブルソートも作成しましょう:
class BubbleSorter implements Sorter {
public void sort(int[] array, BiConsumer<Integer, Integer>... actions) {
int tmp;
boolean swapped;
do {
swapped = false;
for (int i = 1, length = array.length; i < length; ++i) {
if (array[i - 1] > array[i]) {
tmp = array[i];
array[i] = array[i - 1];
array[i - 1] = tmp;
// Swap the other arrays
for (BiConsumer<Integer, Integer> cons : actions) {
cons.accept(i, i - 1);
}
swapped = true;
}
}
} while (swapped);
}
}
これで、長さという単純な条件に基づいて、どちらか一方を簡単に呼び出すことができます。
static void sortArrays(int[] array, BiConsumer<Integer, Integer>... actions){
if(array.length < 1000){
new BubbleSorter().sort(array, actions);
} else {
new SelectionSorter().sort(array, actions);
}
}
そうすれば、ソーターを簡単に呼び出すことができます
Sorter.sortArrays(indexes,
(i, j) -> swapCell(sources, i, j),
(i, j) -> swapCell(targets, i, j)
);
ideone の完全なテストケース(タイムアウトによるサイズの制限)
私はあなたの質問に対する他の解決策を持っています:
private void reOrder(int[] indexes, String[] sources, String[] targets){
int[] reIndexs = new int[indexes.length]; // contain index of item from MIN to MAX
String[] reSources = new String[indexes.length]; // array sources after re-order follow reIndexs
String[] reTargets = new String[indexes.length]; // array targets after re-order follow reIndexs
for (int i=0; i < (indexes.length - 1); i++){
if (i == (indexes.length - 2)){
if (indexes[i] > indexes[i+1]){
reIndexs[i] = i+1;
reIndexs[i+1] = i;
}else
{
reIndexs[i] = i;
reIndexs[i+1] = i+1;
}
}else
{
for (int j=(i+1); j < indexes.length; j++){
if (indexes[i] > indexes[j]){
reIndexs[i] = j;
}else {
reIndexs[i] = i;
}
}
}
}
// Re-order sources array and targets array
for (int index = 0; index < reIndexs.length; index++){
reSources[index] = sources[reIndexs[index]];
reTargets[index] = targets[reIndexs[index]];
}
// Print to view result
System.out.println( Arrays.toString(reIndexs));
System.out.println( Arrays.toString(reSources));
System.out.println( Arrays.toString(reTargets));
}
あなたもあなたの方法で達成することができます。
ここでは、ArrayList myArr
を作成し、インデックス値に基づいて並べ替えてから、ArrayListに満足している場合は、変換を削除するか、配列を使用したい場合は、配列に変換し直しました。
import Java.util.ArrayList;
import Java.util.Arrays;
import Java.util.Collections;
import Java.util.Comparator;
public class StackOverflow {
public static void main(String[] args) {
int[] indexes = new int[]{0,2,8,5};
String[] sources = new String[]{"how", "are", "today", "you"};
String[] targets = new String[]{"I", "am", "thanks", "fine"};
ArrayList<myClass> myArr=new ArrayList<>();
for(int i=0;i<indexes.length;i++) {
myArr.add(new myClass(indexes[i], sources[i], targets[i]));
}
//Collections.sort(myArr,new compareIndex());
// Just for readability of code
Collections.sort(myArr, (mC1, mC2) -> mC1.getX() - mC2.getX());
//Conversion Part
for (int i=0;i<myArr.size();i++){
indexes[i]=myArr.get(i).getX();
sources[i]=myArr.get(i).getSource();
targets[i]=myArr.get(i).getTarget();
}
System.out.println(Arrays.toString(indexes));
System.out.println(Arrays.toString(sources));
System.out.println(Arrays.toString(targets));
}
}
class myClass {
private Integer x;
private String source;
private String target;
public myClass(Integer x,String source,String target){
this.x=x;
this.source=source;
this.target=target;
}
public Integer getX() {
return x;
}
public String getSource() {
return source;
}
public String getTarget() {
return target;
}
}