String
Java에서 두 개의 배열 을 연결해야합니다 .
void f(String[] first, String[] second) {
String[] both = ???
}
가장 쉬운 방법은 무엇입니까?
array1 + array2
연결을 얻지 못했는지 궁금 합니다.
String
Java에서 두 개의 배열 을 연결해야합니다 .
void f(String[] first, String[] second) {
String[] both = ???
}
가장 쉬운 방법은 무엇입니까?
array1 + array2
연결을 얻지 못했는지 궁금 합니다.
답변:
좋은 오래된 Apache Commons Lang 라이브러리에서 한 줄 솔루션을 찾았습니다.
ArrayUtils.addAll(T[], T...)
암호:
String[] both = ArrayUtils.addAll(first, second);
다음은 두 배열을 연결하고 결과를 반환하는 간단한 방법입니다.
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[]
합니다.
또한 가장 일반적인 유형을 결과의 구성 요소 유형으로 선택하여 두 가지 유형의 배열을 연결할 수 있습니다.
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 }));
Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
. 놀랍게도 전에는 본 적이 없습니다. @beaudet 왜 주석이 억제되는지를 고려하여 주석이 훌륭하다고 생각합니다.
여러 배열을 연결하도록 확장 할 수있는 완전 일반 버전을 작성할 수 있습니다. 이 버전은 Java 6을 사용하므로 필요합니다.Arrays.copyOf()
두 버전 모두 중개 List
오브젝트를 작성하지 않고 System.arraycopy()
대형 어레이를 최대한 빨리 복사 하는 데 사용 합니다.
두 배열의 경우 다음과 같습니다.
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;
}
T
로 바꾸십시오 byte
(및을 잃음 <T>
).
ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
concat(ai, ad)
where ai
is Integer[]
and ad
is 와 같이 다른 구성 요소 유형의 배열로 이러한 함수를 호출하면 분명해집니다 Double[]
. (이 경우, type 매개 변수 <T>
는 <? extends Number>
컴파일러 에 의해 해석됩니다 .)로 작성된 Arrays.copyOf
배열은 첫 번째 배열의 구성 요소 유형 (예 : Integer
이 예) 을 갖습니다 . 함수가 두 번째 배열을 복사하려고 ArrayStoreException
할 때가 발생합니다. 해결책은 추가 Class<T> type
매개 변수를 갖는 것 입니다.
Stream
Java 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));
.boxed()
유형 Stream
이어야 IntStream
합니다 Stream.concat
.
a
and b
are int[]
)int[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
System.arrayCopy
. 그러나 특히 느리지는 않습니다. 당신은 아마 이것을을해야 할 매우 많은 시간 거대한 에 배열을 정말 중요 할 수있는 실행 시간 차이의 성능에 민감한 상황.
또는 사랑하는 구아바 와 함께 :
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)
두 줄의 코드로 두 배열을 추가 할 수 있습니다.
String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);
이 방법은 빠르고 효율적인 솔루션이며 기본 유형과 관련된 두 가지 방법이 모두 오버로드 될 수 있습니다.
유용한 목적없이 임시 메모리를 할당해야하므로 ArrayList, 스트림 등과 관련된 솔루션은 피해야합니다.
for
큰 배열에는 효율적이지 않으므로 루프를 피해야 합니다. 내장 된 메소드는 매우 빠른 블록 복사 기능을 사용합니다.
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;
}
null
검사 를 추가 할 수 있습니다 . 그리고 일부 변수를로 설정하십시오 final
.
null
검사는 NPE를 표시하지 않고 숨길 수 있으며 지역 변수에 final을 사용하면 아무런 이점이 없습니다.
최근에 과도한 메모리 회전 문제가 발생했습니다. 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 문은이 특정 최적화의 요점이었습니다. 이 답변을 여기에 남겨 둘 것이지만 조심하십시오!
System.arraycopy
배열의 내용을 복사 한다고 생각 했습니까?
if
문장을 남기는 것이 가장 쉬운 해결책입니다.
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));
both.toArray(new String[0]);
both.toArray(new String[both.size()])
;)
다음은 제네릭이 개선 된 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의 답변 을 참조하십시오 . 경고를 제거 할뿐만 아니라; 또한 짧고 효율적이며 읽기 쉽습니다!
이 방법을 사용하면 타사 클래스를 가져올 필요가 없습니다.
연결을 원한다면 String
두 개의 문자열 배열을 연결하기위한 샘플 코드
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
두 정수 배열을 연결하기위한 샘플 코드
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));
}
}
이 방법으로도 사용할 수 있습니다.
이 긴 목록에 다른 버전을 추가해 주셔서 감사합니다. 나는 모든 대답을보고 서명에 매개 변수가 하나 뿐인 버전을 정말로 원한다고 결정했습니다. 또한 예기치 않은 입력의 경우 현명한 정보로 조기 실패의 이점을 얻기 위해 인수 검사를 추가했습니다.
@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;
}
Arraylist로 변환하고 addAll 메소드를 사용한 다음 다시 배열로 변환 할 수 있습니다.
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
여기 실버 탭이 작성한 의사 코드 솔루션의 작업 코드에서 가능한 구현입니다.
고마워 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 이외의 것에 의존하지 않습니다.
for
루프를 다음과 같이 바꾸는 것이 좋습니다 .for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)
첫 번째 for
루프 를 건너 뛰는 데 사용 합니다 . 의 크기에 비례하여 시간을 절약합니다 arr1
.
이것은 String 배열에 대해 변환 된 함수입니다.
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;
}
어때요?
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 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;
}
질문에 대해 생각하는 또 다른 방법. 둘 이상의 배열을 연결하려면 각 배열의 모든 요소를 나열한 다음 새 배열을 작성해야합니다. 이것은 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
. 그러나 나는 이것이 하나의 아름다움을 가지고 있다고 생각합니다.
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 [] (제로 배열)에서도 작동합니다.