Javaで2つの配列を連結するにはどうすればよいですか?


1366

StringJavaで2つの配列を連結する必要があります。

void f(String[] first, String[] second) {
    String[] both = ???
}

これを行う最も簡単な方法は何ですか?


3
GuavaのBytes.concat
Benページ

1
ここには多くの回答が表示されますが、質問の文言が(「最も簡単な方法」)
ありすぎて

2
ここで何十もの回答がデータを新しい配列にコピーすることです。それは、それが求められていることです。しかし、特にJavaで厳密に必要でないときにデータをコピーすることは悪いことです。代わりに、インデックスを追跡し、2つの配列が結合されているかのように使用します。テクニックを説明するソリューションを追加しました。
ダグラス

12
このような質問には現在50の異なる回答があるため、Javaが単純なarray1 + array2連結を取得できなかったのはなぜでしょうか。
JollyJoker 2017年

2
2行の標準Java(私の答えを参照)で完全にうまく、非常に効率的に行うことができるため、単一のメソッドでそれを実行しても、それほど多くのことは得られません。これらすべての奇妙で素晴らしいソリューションは、少し時間の無駄です。
rghome 2018

回答:


1093

古き良きApache Commons Langライブラリから1行のソリューションを見つけました。
ArrayUtils.addAll(T[], T...)

コード:

String[] both = ArrayUtils.addAll(first, second);

175
それが質問に答えるなら、それはどのように「不正行為」ですか?確かに、追加の依存関係があることはおそらくこの特定の状況ではやり過ぎですが、特にApache Commonsには非常に多くの優れた機能があるため、それが存在することを指摘しても害はありません。
Rob、

33
私は同意します、これは実際には質問に答えていません。高レベルのライブラリはすばらしいものですが、効率的な方法を学びたい場合は、ライブラリメソッドが使用しているコードを確認する必要があります。また、多くの状況では、製品の別のライブラリをただちに通過することはできません。
AdamC、2009年

76
これは良い答えだと思います。POJOソリューションも提供されていますが、OPがそのプログラムでApache Commonsをすでに使用している場合(その人気を考慮してすべて可能)、彼はまだこのソリューションを知らない可能性があります。次に、「この1つのメソッドに依存関係を追加する」のではなく、既存のライブラリをより有効に活用します。
アダム

14
単一のメソッドのライブラリを追加しないことを常に心配している場合、新しいライブラリは追加されません。Apache Commonsにある優れたユーティリティを考えると、最初のユースケースが発生したときに追加することを強くお勧めします。
ヒンドル

6
Apache Commonsを使用することは決して「不正行為」と呼ばれるべきではありません。不要な依存関係を考える開発者の正気に疑問を投げかけます。
ジェリルクック2016

768

2つの配列を連結して結果を返す単純なメソッドを次に示します。

public <T> T[] concatenate(T[] a, T[] b) {
    int aLen = a.length;
    int bLen = b.length;

    @SuppressWarnings("unchecked")
    T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
    System.arraycopy(a, 0, c, 0, aLen);
    System.arraycopy(b, 0, c, aLen, bLen);

    return c;
}

プリミティブデータ型では機能せず、オブジェクト型でのみ機能することに注意してください。

次の少し複雑なバージョンは、オブジェクト配列とプリミティブ配列の両方で機能します。引数の型としてのT代わりにT[]を使用してこれを行います。

また、結果のコンポーネントタイプとして最も一般的なタイプを選択することで、2つの異なるタイプの配列を連結することもできます。

public static <T> T concatenate(T a, T b) {
    if (!a.getClass().isArray() || !b.getClass().isArray()) {
        throw new IllegalArgumentException();
    }

    Class<?> resCompType;
    Class<?> aCompType = a.getClass().getComponentType();
    Class<?> bCompType = b.getClass().getComponentType();

    if (aCompType.isAssignableFrom(bCompType)) {
        resCompType = aCompType;
    } else if (bCompType.isAssignableFrom(aCompType)) {
        resCompType = bCompType;
    } else {
        throw new IllegalArgumentException();
    }

    int aLen = Array.getLength(a);
    int bLen = Array.getLength(b);

    @SuppressWarnings("unchecked")
    T result = (T) Array.newInstance(resCompType, aLen + bLen);
    System.arraycopy(a, 0, result, 0, aLen);
    System.arraycopy(b, 0, result, aLen, bLen);        

    return result;
}

次に例を示します。

Assert.assertArrayEquals(new int[] { 1, 2, 3 }, concatenate(new int[] { 1, 2 }, new int[] { 3 }));
Assert.assertArrayEquals(new Number[] { 1, 2, 3f }, concatenate(new Integer[] { 1, 2 }, new Number[] { 3f }));

1
この提案は、最新のJavaバージョンへの依存度が低いため、気に入っています。私のプロジェクトでは、Anttiによって言及されているような機能の一部が利用できないJavaまたはCLDCプロファイルの古いバージョンを使用してスタックすることがよくあります。
kvn

4
次の行は一般的な部分を壊します:concatenate(new String [] {"1"}、new Object [] {new Object()})
dragon66

@SuppressWarningsアノテーションを使用する必要がないのはいいことです。その解決策を以下に投稿します。
ボーデット

の+1 Array.newInstance(a.getClass().getComponentType(), aLen + bLen);。意外にも、これまで見たことがない。@beaudetなぜ抑制されているのかを考えると、注釈はここで問題ないと思います。
Blake

1
ハ、私を純粋主義者と呼びますが、警告を削除するために警告の抑制を必要としないクリーンなコードを好みます
beaudet

475

任意の数の配列を連結するように拡張することさえできる完全に汎用的なバージョンを書くことが可能です。このバージョンではJava 6が必要です。Arrays.copyOf()

どちらのバージョンも、中間Listオブジェクトの作成を避けて使用しますSystem.arraycopy()大きな配列のコピーを可能な限り高速にするためにします。

2つの配列の場合、次のようになります。

public static <T> T[] concat(T[] first, T[] second) {
  T[] result = Arrays.copyOf(first, first.length + second.length);
  System.arraycopy(second, 0, result, first.length, second.length);
  return result;
}

そして、任意の数の配列(> = 1)の場合、次のようになります。

public static <T> T[] concatAll(T[] first, T[]... rest) {
  int totalLength = first.length;
  for (T[] array : rest) {
    totalLength += array.length;
  }
  T[] result = Arrays.copyOf(first, totalLength);
  int offset = first.length;
  for (T[] array : rest) {
    System.arraycopy(array, 0, result, offset, array.length);
    offset += array.length;
  }
  return result;
}

10
@djBO:プリミティブ型の配列の場合、型ごとにオーバーロードを作成する必要があります。コードをコピーしてそれぞれTを置き換えるだけですbyte(そしてを失う<T>)。
Joachim Sauer、2011年

クラスで<T>演算子型を使用する方法を教えてください。
Johnydep

6
防御のために、これを最初に追加します。if(first == null){if(second == null){return null; } 2番目に戻る。} if(second == null){最初に戻る; }
マラソン

4
@djBo:何について:ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
Sam Goldberg、

18
このアプローチには、異なるコンポーネントタイプの配列でこれらの関数を呼び出すと明らかになるバグがあります。たとえばconcat(ai, ad)aiis Integer[]adis Double[]です。(この場合、型パラメーター<T><? extends Number>コンパイラーによって解決されます。)によって作成された配列Arrays.copyOfは、最初の配列のコンポーネント型になりますInteger(この例では)。関数が2番目の配列をコピーしよArrayStoreExceptionうとすると、がスローされます。解決策は、追加のClass<T> typeパラメーターを持つことです。
T-Bull

457

StreamJava 8での使用:

String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
                      .toArray(String[]::new);

または、次のように使用しflatMapます:

String[] both = Stream.of(a, b).flatMap(Stream::of)
                      .toArray(String[]::new);

ジェネリック型に対してこれを行うには、リフレクションを使用する必要があります。

@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
    size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));

28
これはどれくらい効率的ですか?
Supuhstar、2015年

8
読む価値があります:jaxenter.com/…tl ; dr-ストリームはパフォーマンスが良いかどうか、それはあなたがそれらで何をしているかと問題の制約に依存します(これは常に答えではありませんか?笑)
Trevor Brown

6
さらに、aまたはbがプリミティブ型の配列である場合、それらのストリームは、たとえばパラメーターとしてに渡すことができない.boxed()タイプStreamではなく、タイプである必要がありIntStreamますStream.concat
ウィルハードウィックスミス

17
@Willハードウィック・スミス:いいえ、あなただけの場合は例えば、右のストリームクラスを選択する必要がありabされint[]、使用int[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
ホルガー

3
@Supuhstar:おそらくほど速くはありませんSystem.arrayCopy。しかし、特に遅くはありません。あなたはおそらくこれを行うには非常に多くの時間を巨大で配列本当に問題には、実行時間差のパフォーマンスに敏感なコンテキスト。
Lii 2017

191

または最愛のグアバと

String[] both = ObjectArrays.concat(first, second, String.class);

また、プリミティブ配列には次のバージョンがあります。

  • Booleans.concat(first, second)
  • Bytes.concat(first, second)
  • Chars.concat(first, second)
  • Doubles.concat(first, second)
  • Shorts.concat(first, second)
  • Ints.concat(first, second)
  • Longs.concat(first, second)
  • Floats.concat(first, second)

私がグアバを愛しているのと同じくらい、Apache Commonsのメソッドはnullableをよりよく扱います。
Ravi Wallau、2013年

7
ライブラリを使用するのは良いことですが、問題が抽象化されているのは残念です。したがって、根本的な解決策はとらえどころのないままです。
user924272 2014

51
抽象化の問題は何ですか?Dunnoは、ここでホイールを再発明することについて何をしていますか。問題を学びたい場合は、ソースを確認するか、それを読んでください。プロのコードは高レベルのライブラリを使用している必要があります。Google内で開発されている場合はさらに優れています。
Breno Salgado、2014

@RaviWallauこれを行うクラスにリンクできますか?
セバスチャントロンプ

1
@SébastienTrompこれは、この質問に対する最高のソリューションです-ArrayUtils。
Ravi Wallau、2018年

70

2つの配列を2行のコードで追加できます。

String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);

これは高速で効率的なソリューションであり、プリミティブ型で機能し、関連する2つのメソッドがオーバーロードされます。

ArrayList、ストリームなどを含むソリューションは、有用な目的のために一時メモリを割り当てる必要があるため、避けてください。

for大規模な配列のループは効率的ではないため、避ける必要があります。組み込みのメソッドは、非常に高速なブロックコピー機能を使用します。


1
これは最良のソリューションの1つです。100%標準Java。高速/効率的。より多くの賛成を得るべきです!
Shebla Tsama

58

Java APIの使用:

String[] f(String[] first, String[] second) {
    List<String> both = new ArrayList<String>(first.length + second.length);
    Collections.addAll(both, first);
    Collections.addAll(both, second);
    return both.toArray(new String[both.size()]);
}

13
単純ですが、ArrayListの配列を作成し、toArrayメソッドの別の配列を生成するため、非効率的です。しかし、それは読みやすいのでまだ有効です。
PhoneixS 2014年

1
文字列とオブジェクトに適用できます(質問が必要)が、プライマリタイプ(intなど)にはaddAllメソッドがありません
joro

この記事で詳しく説明したように、私たちの素朴な直観に反する場合でも、を使用both.toArray(new String[0])するとが速くなりboth.toArray(new String[both.size()])ます。そのため、最適化時に実際のパフォーマンスを測定することが非常に重要です。または、より複雑なバリアントの利点が証明できない場合は、より単純な構成を使用します。
ホルガー

42

100%古いJavaなしの ソリューションSystem.arraycopy(たとえば、GWTクライアントでは使用できません):

static String[] concat(String[]... arrays) {
    int length = 0;
    for (String[] array : arrays) {
        length += array.length;
    }
    String[] result = new String[length];
    int pos = 0;
    for (String[] array : arrays) {
        for (String element : array) {
            result[pos] = element;
            pos++;
        }
    }
    return result;
}

File []のために私のものを作り直しましたが、それは同じです。解決策をありがとう
ShadowFlame

5
おそらくかなり非効率的です。
JonasCz-モニカを2015年

nullチェックを追加することもできます。そして、おそらくいくつかの変数をに設定しますfinal
Tripp Kinetics

@TrippKinetics nullチェックは、NPEを表示するのではなく非表示にし、ローカル変数にfinalを使用しても、(まだ)メリットはありません。
Maarten Bodewes

1
@Maarten Bodewes for-eachは、Javaの最新バージョンのインデックス付きループと同時に実行されることがわかります(ベンチマークを行った場合)。オプティマイザがそれを処理します。
rghome

33

私は最近、過度のメモリローテーションの問題と戦いました。aおよび/またはbが一般的に空であることがわかっている場合、silvertabのコードの別の適応を以下に示します(一般化されています)。

private static <T> T[] concatOrReturnSame(T[] a, T[] b) {
    final int alen = a.length;
    final int blen = b.length;
    if (alen == 0) {
        return b;
    }
    if (blen == 0) {
        return a;
    }
    final T[] result = (T[]) java.lang.reflect.Array.
            newInstance(a.getClass().getComponentType(), alen + blen);
    System.arraycopy(a, 0, result, 0, alen);
    System.arraycopy(b, 0, result, alen, blen);
    return result;
}

編集:この投稿の以前のバージョンでは、このようなアレイの再利用は明確に文書化する必要があると述べていました。Maartenがコメントで指摘しているように、一般的にはifステートメントを削除する方がよいため、ドキュメントを用意する必要がなくなります。しかし、繰り返しになりますが、これらのifステートメントがそもそもこの特定の最適化の要点でした。この答えはここに残しておきますが、注意してください。


5
ただし、これは同じ配列を返し、返された配列の値を変更すると、返された入力配列の同じ位置の値が変更されることを意味します。
Lorenzo Boccaccia

はい-アレイの再利用に関する私の投稿の最後にあるコメントを参照してください。このソリューションによって課せられるメンテナンスオーバーヘッドは、私たちの特定のケースではそれだけの価値がありましたが、防御コピーはおそらくほとんどの場合に使用されるべきです。
ボレー

ロレンソ/ボレー、配列の再利用を引き起こすコードのどの部分を説明できますか?System.arraycopy配列の内容をコピーすると思いましたか?
Rosdi Kasim 2010

4
呼び出し元は通常、concat()の呼び出しが新しく割り当てられた配列を返すことを期待します。ただし、aまたはbのいずれかがnullの場合、concat()は渡された配列の1つを返します。この再利用は予想外の可能性があります。(そうです、arraycopyはコピーのみを行います。再利用はaまたはbを直接返すことから発生します。)
volley

コードはできるだけ自明でなければなりません。コードを読んでいる人は、呼び出された関数のJavaDocを検索して、ある特定の条件に対して1つのことを行い、別の条件に対して別のことを行うことを見つける必要はありません。要するに、このようなデザインの問題をコメントで修正することは通常できません。2つのifステートメントを省略するだけで簡単に修正できます。
Maarten Bodewes

27

機能のJavaライブラリは、連結のような便利なメソッドを持つ配列を装備配列ラッパークラスを持っています。

import static fj.data.Array.array;

...その後

Array<String> both = array(first).append(array(second));

アンラップされた配列を元に戻すには、次を呼び出します

String[] s = both.array();

27
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));

both.toArray(new String[0]);

3
答えは素晴らしいですが、少し壊れています。完璧にするには、必要な型の配列をtoArray()に渡す必要があります。上記の例では、コードは次のようになります(新しいString [0])を参照both.toArray:stackoverflow.com/questions/4042434/...
Ronen氏Rabinovici

なぜこの回答の評価が高くないのかわからない... @RonenRabinoviciによって提案された変更が必要なようです
drmrbrewer

4
または、長さ0の配列を不必要に割り当てないでくださいboth.toArray(new String[both.size()])。;)
Honza

1
@Honzaの推奨
Holger

こんにちは@Honza、同じことをして3行のプリミティブ整数配列を返すことは可能ですか?
jumping_monkey

18

Streamを使用したJava8の別の方法

  public String[] concatString(String[] a, String[] b){ 
    Stream<String> streamA = Arrays.stream(a);
    Stream<String> streamB = Arrays.stream(b);
    return Stream.concat(streamA, streamB).toArray(String[]::new); 
  }

17

ジェネリックが後付けされた、silvertabのソリューションを以下に示します。

static <T> T[] concat(T[] a, T[] b) {
    final int alen = a.length;
    final int blen = b.length;
    final T[] result = (T[]) java.lang.reflect.Array.
            newInstance(a.getClass().getComponentType(), alen + blen);
    System.arraycopy(a, 0, result, 0, alen);
    System.arraycopy(b, 0, result, alen, blen);
    return result;
}

注:Java 6ソリューションについては、Joachimの回答を参照してください。警告を排除するだけでなく、また、短く、効率的で読みやすくなっています。


このメソッドの警告を抑制することはできますが、それ以外にできることはあまりありません。配列とジェネリックは実際には混合しません。
Dan Dyer

3
Arrays.copyOf()を使用すると、チェックされていない警告を削除できます。実装については私の回答を参照してください。
ヨアヒムザウアー

@SuppressWarnings( "unchecked")
Mark Renouf、

13

この方法を使用すると、サードパーティのクラスをインポートする必要がありません。

連結したい場合 String

2つの文字列配列を連結するためのサンプルコード

public static String[] combineString(String[] first, String[] second){
        int length = first.length + second.length;
        String[] result = new String[length];
        System.arraycopy(first, 0, result, 0, first.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

連結したい場合 Int

2つの整数配列を連結するためのサンプルコード

public static int[] combineInt(int[] a, int[] b){
        int length = a.length + b.length;
        int[] result = new int[length];
        System.arraycopy(a, 0, result, 0, a.length);
        System.arraycopy(b, 0, result, a.length, b.length);
        return result;
    }

ここにメインメソッドがあります

    public static void main(String[] args) {

            String [] first = {"a", "b", "c"};
            String [] second = {"d", "e"};

            String [] joined = combineString(first, second);
            System.out.println("concatenated String array : " + Arrays.toString(joined));

            int[] array1 = {101,102,103,104};
            int[] array2 = {105,106,107,108};
            int[] concatenateInt = combineInt(array1, array2);

            System.out.println("concatenated Int array : " + Arrays.toString(concatenateInt));

        }
    }  

この方法でも使用できます。


11

このすでに長いリストに別のバージョンを追加したことを許してください。私はすべての答えを見て、署名にパラメーターが1つだけあるバージョンが本当に必要だと判断しました。また、予期しない入力があった場合の賢明な情報による早期の失敗から利益を得るために、いくつかの引数チェックを追加しました。

@SuppressWarnings("unchecked")
public static <T> T[] concat(T[]... inputArrays) {
  if(inputArrays.length < 2) {
    throw new IllegalArgumentException("inputArrays must contain at least 2 arrays");
  }

  for(int i = 0; i < inputArrays.length; i++) {
    if(inputArrays[i] == null) {
      throw new IllegalArgumentException("inputArrays[" + i + "] is null");
    }
  }

  int totalLength = 0;

  for(T[] array : inputArrays) {
    totalLength += array.length;
  }

  T[] result = (T[]) Array.newInstance(inputArrays[0].getClass().getComponentType(), totalLength);

  int offset = 0;

  for(T[] array : inputArrays) {
    System.arraycopy(array, 0, result, offset, array.length);

    offset += array.length;
  }

  return result;
}

nullチェックを実行しているのと同じループで長さを合計します-これは、ここでの他の回答の本当に良い要約です。「int」などの組み込み型もIntegerオブジェクトに変更せずに処理できると思います。これは、すべてを単にArrayListsに変更するのではなく、配列として扱う唯一の理由です。呼び出し側が、彼はそれを実行し、エラーを見る前に少なくとも2列に渡す必要がある知っているが、それは....ループのコードを複雑にしても、あなたの方法は、2つの配列と(...)パラメータを取ることができる
ビル・Kを

11

これをArraylistに変換して、addAllメソッドを使用してから、配列に変換してみることができます。

List list = new ArrayList(Arrays.asList(first));
  list.addAll(Arrays.asList(second));
  String[] both = list.toArray();

良い解決策-ArrayListsを優先して配列を完全に回避するようにコードをリファクタリングする場合はより良いでしょうが、それは "Answer"の制御外であり、質問者次第です。
Bill K

私はそれが機能するために4つの追加の一時オブジェクトを必要とすると思います。
rghome 2018

@rghome、少なくとも、そのような単純なタスクを実装するために追加のライブラリを必要としない
Farid

9

Java 8+ストリームを使用して、次の関数を記述できます。

private static String[] concatArrays(final String[]... arrays) {
    return Arrays.stream(arrays)
         .flatMap(Arrays::stream)
         .toArray(String[]::new);
}

7

ここで、silvertabによって作成された疑似コードソリューションの作業コードの可能な実装。

silvertab、ありがとう!

public class Array {

   public static <T> T[] concat(T[] a, T[] b, ArrayBuilderI<T> builder) {
      T[] c = builder.build(a.length + b.length);
      System.arraycopy(a, 0, c, 0, a.length);
      System.arraycopy(b, 0, c, a.length, b.length);
      return c;
   }
}

次はビルダーインターフェイスです。

注:Javaでは実行できないため、ビルダーが必要です。

new T[size]

ジェネリック型の消去のため:

public interface ArrayBuilderI<T> {

   public T[] build(int size);
}

ここでは、インターフェースを実装してInteger配列を構築する具体的なビルダーを示します。

public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {

   @Override
   public Integer[] build(int size) {
      return new Integer[size];
   }
}

そして最後にアプリケーション/テスト:

@Test
public class ArrayTest {

   public void array_concatenation() {
      Integer a[] = new Integer[]{0,1};
      Integer b[] = new Integer[]{2,3};
      Integer c[] = Array.concat(a, b, new IntegerArrayBuilder());
      assertEquals(4, c.length);
      assertEquals(0, (int)c[0]);
      assertEquals(1, (int)c[1]);
      assertEquals(2, (int)c[2]);
      assertEquals(3, (int)c[3]);
   }
}

7

これはワンライナーである必要があります。

public String [] concatenate (final String array1[], final String array2[])
{
    return Stream.concat(Stream.of(array1), Stream.of(array2)).toArray(String[]::new);
}

6

うわー!外部の依存関係に依存するいくつかの単純なものを含め、ここには多くの複雑な答えがあります。このようにするのはどうですか:

String [] arg1 = new String{"a","b","c"};
String [] arg2 = new String{"x","y","z"};

ArrayList<String> temp = new ArrayList<String>();
temp.addAll(Arrays.asList(arg1));
temp.addAll(Arrays.asList(arg2));
String [] concatedArgs = temp.toArray(new String[arg1.length+arg2.length]);

1
..しかし、非効率的で遅い。
JonasCz-モニカを2015年

6

これは機能しますが、独自のエラーチェックを挿入する必要があります。

public class StringConcatenate {

    public static void main(String[] args){

        // Create two arrays to concatenate and one array to hold both
        String[] arr1 = new String[]{"s","t","r","i","n","g"};
        String[] arr2 = new String[]{"s","t","r","i","n","g"};
        String[] arrBoth = new String[arr1.length+arr2.length];

        // Copy elements from first array into first part of new array
        for(int i = 0; i < arr1.length; i++){
            arrBoth[i] = arr1[i];
        }

        // Copy elements from second array into last part of new array
        for(int j = arr1.length;j < arrBoth.length;j++){
            arrBoth[j] = arr2[j-arr1.length];
        }

        // Print result
        for(int k = 0; k < arrBoth.length; k++){
            System.out.print(arrBoth[k]);
        }

        // Additional line to make your terminal look better at completion!
        System.out.println();
    }
}

おそらく最も効率的ではありませんが、Java独自のAPI以外には依存していません。


2
+1。なお、第2交換する方が良いだろうfor。それとループfor(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
bancer

String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)最初のforループをスキップするために使用します。のサイズに比例して時間を節約しますarr1
John Meyer、

5

これは文字列配列に変換された関数です:

public String[] mergeArrays(String[] mainArray, String[] addArray) {
    String[] finalArray = new String[mainArray.length + addArray.length];
    System.arraycopy(mainArray, 0, finalArray, 0, mainArray.length);
    System.arraycopy(addArray, 0, finalArray, mainArray.length, addArray.length);

    return finalArray;
}

5

単純にどうですか

public static class Array {

    public static <T> T[] concat(T[]... arrays) {
        ArrayList<T> al = new ArrayList<T>();
        for (T[] one : arrays)
            Collections.addAll(al, one);
        return (T[]) al.toArray(arrays[0].clone());
    }
}

そして、ただArray.concat(arr1, arr2)arr1arr2が同じ型である限り、これにより、両方の配列を含む同じ型の別の配列が得られます。


パフォーマンス上の理由から、ArrayListは定義により新しい配列を割り当て、現在の配列がいっぱいになるたびにその要素をコピーするため、ArrayListの最終的なサイズを事前に計算します。そうでなければ、私はこのような問題を受けないLinkedListのためにまっすぐに行くだろう
USR-ローカルΕΨΗΕΛΩΝ

5

@SuppressWarningsアノテーションを必要とせずに高性能のSystem.arraycopyを使用する一般的な静的バージョン:

public static <T> T[] arrayConcat(T[] a, T[] b) {
    T[] both = Arrays.copyOf(a, a.length + b.length);
    System.arraycopy(b, 0, both, a.length, b.length);
    return both;
}

4
public String[] concat(String[]... arrays)
{
    int length = 0;
    for (String[] array : arrays) {
        length += array.length;
    }
    String[] result = new String[length];
    int destPos = 0;
    for (String[] array : arrays) {
        System.arraycopy(array, 0, result, destPos, array.length);
        destPos += array.length;
    }
    return result;
}

4

これは、Joachim SauerのconcatAllを少し改良したバージョンです。実行時に使用できる場合は、Java 6のSystem.arraycopyを使用してJava 5または6で動作します。この方法(IMHO)は、Android <9(System.arraycopyがない)で動作するため、Androidに最適ですが、可能であればより高速な方法を使用します。

  public static <T> T[] concatAll(T[] first, T[]... rest) {
    int totalLength = first.length;
    for (T[] array : rest) {
      totalLength += array.length;
    }
    T[] result;
    try {
      Method arraysCopyOf = Arrays.class.getMethod("copyOf", Object[].class, int.class);
      result = (T[]) arraysCopyOf.invoke(null, first, totalLength);
    } catch (Exception e){
      //Java 6 / Android >= 9 way didn't work, so use the "traditional" approach
      result = (T[]) java.lang.reflect.Array.newInstance(first.getClass().getComponentType(), totalLength);
      System.arraycopy(first, 0, result, 0, first.length);
    }
    int offset = first.length;
    for (T[] array : rest) {
      System.arraycopy(array, 0, result, offset, array.length);
      offset += array.length;
    }
    return result;
  }

1
良い一般的なアイデアですが、実装するすべての人に、リフレクションによって両方を行うバージョンよりも、copyOfバージョンとnon-copyOfバージョンを優先します。
rektide

4

質問について考える別の方法。2つ以上の配列を連結するには、各配列のすべての要素をリストしてから、新しい配列を作成する必要があります。これは、a List<T>を作成し、それを呼び出すように聞こえますtoArray。他のいくつかの答えはを使用していますがArrayList、それは問題ありません。しかし、私たち自身の実装はどうですか?それは難しくありません:

private static <T> T[] addAll(final T[] f, final T...o){
    return new AbstractList<T>(){

        @Override
        public T get(int i) {
            return i>=f.length ? o[i - f.length] : f[i];
        }

        @Override
        public int size() {
            return f.length + o.length;
        }

    }.toArray(f);
}

上記はを使用するソリューションと同等であると思いますSystem.arraycopy。しかし、これはそれ自身の美しさを持っていると思います。


4

どのように:

public String[] combineArray (String[] ... strings) {
    List<String> tmpList = new ArrayList<String>();
    for (int i = 0; i < strings.length; i++)
        tmpList.addAll(Arrays.asList(strings[i]));
    return tmpList.toArray(new String[tmpList.size()]);
}

4

複数の配列を結合できる単純なバリエーション:

public static String[] join(String[]...arrays) {

    final List<String> output = new ArrayList<String>();

    for(String[] array : arrays) {
        output.addAll(Arrays.asList(array));
    }

    return output.toArray(new String[output.size()]);
}

3

Java独自のAPIのみを使用:


String[] join(String[]... arrays) {
  // calculate size of target array
  int size = 0;
  for (String[] array : arrays) {
    size += array.length;
  }

  // create list of appropriate size
  java.util.List list = new java.util.ArrayList(size);

  // add arrays
  for (String[] array : arrays) {
    list.addAll(java.util.Arrays.asList(array));
  }

  // create and return final array
  return list.toArray(new String[size]);
}

現在、このコードは最も効率的ではありませんが、標準のJavaクラスのみに依存しており、理解しやすくなっています。これは、任意の数のString [](ゼロ配列でも)で機能します。


15
不要なすべてのListオブジェクトの作成のためにこれに反対票を投じなければなりませんでした。
アウトロープログラマ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.