String
Java で 2 つの配列を連結する必要があります。
void f(String[] first, String[] second) {
String[] both = ???
}
これを行う最も簡単な方法は何ですか?
String
Java で 2 つの配列を連結する必要があります。
void f(String[] first, String[] second) {
String[] both = ???
}
これを行う最も簡単な方法は何ですか?
古き良きApache Commons Langライブラリから1行のソリューションを見つけました。
ArrayUtils.addAll(T[], T...)
コード:
String[] both = ArrayUtils.addAll(first, second);
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 }));
または最愛のグアバと一緒に:
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)
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()]);
}
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;
}
私は最近、過剰なメモリローテーションの問題と戦ってきました。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 ステートメントは、そもそもこの特定の最適化の要点でした。この答えはここに残しておきますが、用心してください!
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));
both.toArray(new String[0]);
Functional Javaライブラリには、連結などの便利なメソッドを配列に装備する配列ラッパー クラスがあります。
import static fj.data.Array.array;
...その後
Array<String> both = array(first).append(array(second));
アンラップされた配列を元に戻すには、呼び出します
String[] s = both.array();
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);
}
これは、ジェネリックを改造した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 の回答を参照してください。警告がなくなるだけではありません。また、より短く、より効率的で読みやすくなっています。
それをArraylistに変換してみて、addAllメソッドを使用してから配列に戻すことができます。
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
このすでに長いリストにさらに別のバージョンを追加することをお許しください。私はすべての回答を見て、署名にパラメーターが 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;
}
これは、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]);
}
}
わお!ここには、外部依存関係に依存するいくつかの単純なものを含む、複雑な答えがたくさんあります。次のようにしたらどうですか。
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]);
これは機能しますが、独自のエラー チェックを挿入する必要があります。
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 以外には依存していません。
単純にどうですか
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)
。arr1
とが同じ型である限り、arr2
両方の配列を含む同じ型の別の配列が得られます。
複数の配列を結合できる単純なバリエーション:
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()]);
}
これは、文字列配列の変換された関数です。
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;
}
これはAbacusUtilによるコードです。
String[] a = {"a", "b", "c"};
String[] b = {"1", "2", "3"};
String[] c = N.concat(a, b); // c = ["a", "b", "c", "1", "2", "3"]
// N.concat(...) is null-safety.
a = null;
c = N.concat(a, b); // c = ["1", "2", "3"]
どうですか :
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()]);
}
質問について考える別の方法。2 つ以上の配列を連結するには、各配列のすべての要素をリストしてから、新しい配列を作成する必要があります。List<T>
これは、 a を作成してからそれを呼び出すように聞こえます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
。しかし、これには独自の美しさがあると思います。
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;
}
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;
}
すべての答えは、データをコピーして新しい配列を作成することです。これは厳密には必要ではなく、配列がかなり大きい場合は絶対にやりたくないことです。Java の作成者は、配列のコピーが無駄であることをすでに知っていたため、必要なときに Java の外部でコピーを行うために System.arrayCopy() を提供してくれました。
データをコピーする代わりに、データをそのままにして、そこからデータを引き出すことを検討してください。プログラマーが整理したいという理由だけでデータの場所をコピーすることは、必ずしも賢明ではありません。
// I have arrayA and arrayB; would like to treat them as concatenated
// but leave my damn bytes where they are!
Object accessElement ( int index ) {
if ( index < 0 ) throw new ArrayIndexOutOfBoundsException(...);
// is reading from the head part?
if ( index < arrayA.length )
return arrayA[ index ];
// is reading from the tail part?
if ( index < ( arrayA.length + arrayB.length ) )
return arrayB[ index - arrayA.length ];
throw new ArrayIndexOutOfBoundsException(...); // index too large
}
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[] (ゼロ配列でも) に対して機能します。
配列がnullになる可能性がある場合に対処する必要があることがわかりました...
private double[] concat (double[]a,double[]b){
if (a == null) return b;
if (b == null) return a;
double[] r = new double[a.length+b.length];
System.arraycopy(a, 0, r, 0, a.length);
System.arraycopy(b, 0, r, a.length, b.length);
return r;
}
private double[] copyRest (double[]a, int start){
if (a == null) return null;
if (start > a.length)return null;
double[]r = new double[a.length-start];
System.arraycopy(a,start,r,0,a.length-start);
return r;
}
型に依存しないバリエーション (更新 - T をインスタンス化してくれた Volley に感謝):
@SuppressWarnings("unchecked")
public static <T> T[] join(T[]...arrays) {
final List<T> output = new ArrayList<T>();
for(T[] array : arrays) {
output.addAll(Arrays.asList(array));
}
return output.toArray((T[])Array.newInstance(
arrays[0].getClass().getComponentType(), output.size()));
}
これを行う簡単だが非効率的な方法 (ジェネリックは含まれません):
ArrayList baseArray = new ArrayList(Arrays.asList(array1));
baseArray.addAll(Arrays.asList(array2));
String concatenated[] = (String []) baseArray.toArray(new String[baseArray.size()]);
Import java.util.*;
String array1[] = {"bla","bla"};
String array2[] = {"bla","bla"};
ArrayList<String> tempArray = new ArrayList<String>(Arrays.asList(array1));
tempArray.addAll(Arrays.asList(array2));
String array3[] = films.toArray(new String[1]); // size will be overwritten if needed
String を好みのタイプ/クラスに置き換えることができます
これはより短く、より良くできると確信していますが、うまくいき、さらに整理するのが面倒です...
ソリューションで ArrayLists を使用したい場合は、これを試すことができます。
public final String [] f(final String [] first, final String [] second) {
// Assuming non-null for brevity.
final ArrayList<String> resultList = new ArrayList<String>(Arrays.asList(first));
resultList.addAll(new ArrayList<String>(Arrays.asList(second)));
return resultList.toArray(new String [resultList.size()]);
}
もう 1 つは SilverTab の提案に基づいていますが、x 個の引数をサポートし、Java 6 を必要としないように作成されています。これも一般的ではありませんが、一般的にできると確信しています。
private byte[] concat(byte[]... args)
{
int fulllength = 0;
for (byte[] arrItem : args)
{
fulllength += arrItem.length;
}
byte[] retArray = new byte[fulllength];
int start = 0;
for (byte[] arrItem : args)
{
System.arraycopy(arrItem, 0, retArray, start, arrItem.length);
start += arrItem.length;
}
return retArray;
}
public int[] mergeArrays(int [] a, int [] b) {
int [] merged = new int[a.length + b.length];
int i = 0, k = 0, l = a.length;
int j = a.length > b.length ? a.length : b.length;
while(i < j) {
if(k < a.length) {
merged[k] = a[k];
k++;
}
if((l - a.length) < b.length) {
merged[l] = b[l - a.length];
l++;
}
i++;
}
return merged;
}
私が見つけることができる最も簡単な方法は次のとおりです。
List allFiltersList = Arrays.asList(regularFilters);
allFiltersList.addAll(Arrays.asList(preFiltersArray));
Filter[] mergedFilterArray = (Filter[]) allFiltersList.toArray();
Object[] mixArray(String[] a, String[] b)
String[] s1 = a;
String[] s2 = b;
Object[] result;
List<String> input = new ArrayList<String>();
for (int i = 0; i < s1.length; i++)
{
input.add(s1[i]);
}
for (int i = 0; i < s2.length; i++)
{
input.add(s2[i]);
}
result = input.toArray();
return result;
これはintでのみ機能しますが、アイデアは一般的です
public static int[] junta(int[] v, int[] w) {
int[] junta = new int[v.length + w.length];
for (int i = 0; i < v.length; i++) {
junta[i] = v[i];
}
for (int j = v.length; j < junta.length; j++) {
junta[j] = w[j - v.length];
}
Object[] obj = {"hi","there"};
Object[] obj2 ={"im","fine","what abt u"};
Object[] obj3 = new Object[obj.length+obj2.length];
for(int i =0;i<obj3.length;i++)
obj3[i] = (i<obj.length)?obj[i]:obj2[i-obj.length];
以下のコードをテストし、問題なく動作しました
また、ライブラリを使用しています: org.apache.commons.lang.ArrayUtils
public void testConcatArrayString(){
String[] a = null;
String[] b = null;
String[] c = null;
a = new String[] {"1","2","3","4","5"};
b = new String[] {"A","B","C","D","E"};
c = (String[]) ArrayUtils.addAll(a, b);
if(c!=null){
for(int i=0; i<c.length; i++){
System.out.println("c[" + (i+1) + "] = " + c[i]);
}
}
}
よろしく
これを試すことができます
public static Object[] addTwoArray(Object[] objArr1, Object[] objArr2){
int arr1Length = objArr1!=null && objArr1.length>0?objArr1.length:0;
int arr2Length = objArr2!=null && objArr2.length>0?objArr2.length:0;
Object[] resutlentArray = new Object[arr1Length+arr2Length];
for(int i=0,j=0;i<resutlentArray.length;i++){
if(i+1<=arr1Length){
resutlentArray[i]=objArr1[i];
}else{
resutlentArray[i]=objArr2[j];
j++;
}
}
return resutlentArray;
}
あなたの配列を型キャストすることができます!!!
ラムダを使用して、一連の配列をコンパクト、高速、タイプセーフに連結します
@SafeVarargs
public static <T> T[] concat( T[]... arrays ) {
return( Stream.of( arrays ).reduce( ( arr1, arr2 ) -> {
T[] rslt = Arrays.copyOf( arr1, arr1.length + arr2.length );
System.arraycopy( arr2, 0, rslt, arr1.length, arr2.length );
return( rslt );
} ).orElse( null ) );
};
null
引数なしで呼び出すと戻ります
例えば。3 つの配列の例:
String[] a = new String[] { "a", "b", "c", "d" };
String[] b = new String[] { "e", "f", "g", "h" };
String[] c = new String[] { "i", "j", "k", "l" };
concat( a, b, c ); // [a, b, c, d, e, f, g, h, i, j, k, l]
「…おそらく唯一の一般的で型安全な方法」 – 適合:
Number[] array1 = { 1, 2, 3 };
Number[] array2 = { 4.0, 5.0, 6.0 };
Number[] array = concat( array1, array2 ); // [1, 2, 3, 4.0, 5.0, 6.0]
このエレガントなソリューションを見てください(char以外のタイプが必要な場合は、変更してください):
private static void concatArrays(char[] destination, char[]... sources) {
int currPos = 0;
for (char[] source : sources) {
int length = source.length;
System.arraycopy(source, 0, destination, currPos, length);
currPos += length;
}
}
配列のカウントごとに連結できます。
トリックを行う必要があります。これは、String[] が最初で String[] が 2 番目であると想定しています。
List<String> myList = new ArrayList<String>(Arrays.asList(first));
myList.addAll(new ArrayList<String>(Arrays.asList(second)));
String[] both = myList.toArray(new String[myList.size()]);
Haskell では、そのようなこと[a, b, c] ++ [d, e]
を行って を取得でき[a, b, c, d, e]
ます。これらは連結された Haskell リストですが、Java で配列用の同様の演算子が見られると非常に便利です。そう思いませんか?これはエレガントで、シンプルで、汎用的であり、実装するのはそれほど難しくありません。
必要に応じて、Alexander Hristov のHacking the OpenJDK compilerでの作業を参照することをお勧めします。javac ソースを変更して新しいオペレーターを作成する方法を説明しています。彼の例は、'**' 演算子 where i ** j = Math.pow(i, j)
. この例を使用して、同じ型の 2 つの配列を連結する演算子を実装できます。
これを行うと、カスタマイズされた javac にバインドされてコードがコンパイルされますが、生成されたバイトコードは任意の JVM で認識されます。
もちろん、ソースレベルで独自の配列連結メソッドを実装できます。他の回答でそれを行う方法の例がたくさんあります!
追加できる便利な演算子はたくさんありますが、これはその 1 つです。
これが私のために働いたものです:
String[] data=null;
String[] data2=null;
ArrayList<String> data1 = new ArrayList<String>();
for(int i=0; i<2;i++) {
data2 = input.readLine().split(",");
data1.addAll(Arrays.asList(data2));
data= data1.toArray(new String[data1.size()]);
}