Ik moet twee String
-arrays samenvoegen in Java.
void f(String[] first, String[] second) {
String[] both = ???
}
Wat is de gemakkelijkste manier om dit te doen?
Antwoord 1, autoriteit 100%
Ik heb een éénregelige oplossing gevonden uit de goede oude Apache Commons Lang-bibliotheek.ArrayUtils.addAll(T[], T...)
Code:
String[] both = ArrayUtils.addAll(first, second);
Antwoord 2, autoriteit 66%
Hier is een eenvoudige methode die twee arrays samenvoegt en het resultaat retourneert:
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;
}
Houd er rekening mee dat het niet werkt met primitieve gegevenstypen, alleen met objecttypen.
De volgende iets gecompliceerdere versie werkt met zowel object- als primitieve arrays. Het doet dit door T
te gebruiken in plaats van T[]
als argumenttype.
Het maakt het ook mogelijk om arrays van twee verschillende typen samen te voegen door het meest algemene type te kiezen als het componenttype van het resultaat.
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;
}
Hier is een voorbeeld:
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 }));
Antwoord 3, autoriteit 44%
Stream
in Java 8:
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);
Of zo, met flatMap
:
String[] both = Stream.of(a, b).flatMap(Stream::of)
.toArray(String[]::new);
Om dit voor een generiek type te doen, moet je reflectie gebruiken:
@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));
Antwoord 4, autoriteit 41%
Het is mogelijk om een volledig generieke versie te schrijven die zelfs kan worden uitgebreid om een willekeurig aantal arrays samen te voegen. Deze versies vereisen Java 6, omdat ze Arrays.copyOf()
Beide versies vermijden het maken van tussenliggende List
-objecten en gebruiken System.arraycopy()
om ervoor te zorgen dat het kopiëren van grote arrays zo snel mogelijk gaat.
Voor twee arrays ziet het er als volgt uit:
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;
}
En voor een willekeurig aantal arrays (>=1) ziet het er als volgt uit:
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;
}
Antwoord 5, autoriteit 17%
of met de geliefde Guava :
String[] both = ObjectArrays.concat(first, second, String.class);
Er zijn ook versies voor primitieve arrays:
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)
Antwoord 6, Autoriteit 10%
U kunt de twee arrays in twee regels code toevoegen.
String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);
Dit is een snelle en efficiënte oplossing en zal werken voor primitieve typen, evenals de betrokken methoden zijn overbelast.
U moet oplossingen vermijden met arraylisten, streams, enz. Omdat deze tijdelijk geheugen nodig hebben voor geen nuttig doel.
U moet vermijden for
loops voor grote arrays, omdat deze niet efficiënt zijn. De ingebouwde methoden gebruiken blokkopiefuncties die extreem snel zijn.
Antwoord 7, Autoriteit 5%
Gebruik van de 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()]);
}
Antwoord 8, autoriteit 4%
Een oplossing 100% oude javaen zonderSystem.arraycopy
(bijvoorbeeld niet beschikbaar in de GWT-client):
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;
}
Antwoord 9, autoriteit 3%
Ik heb onlangs problemen gehad met overmatige geheugenrotatie. Als bekend is dat a en/of b vaak leeg zijn, is hier nog een aanpassing van de code van silvertab (ook gegenereerd):
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;
}
Bewerken: in een eerdere versie van dit bericht stond dat hergebruik van arrays zoals dit duidelijk moet worden gedocumenteerd. Zoals Maarten in de opmerkingen aangeeft, zou het over het algemeen beter zijn om de if-statements gewoon te verwijderen, waardoor de noodzaak voor documentatie vervalt. Maar nogmaals, die if-statements waren in de eerste plaats het hele punt van deze specifieke optimalisatie. Ik laat dit antwoord hier achter, maar wees voorzichtig!
Antwoord 10, autoriteit 2%
De Functionele Java-bibliotheek heeft een array-wrapperklasse die arrays uitrust met handige methoden zoals concatenatie.
import static fj.data.Array.array;
…en dan
Array<String> both = array(first).append(array(second));
Om de uitgepakte array weer tevoorschijn te halen, bel
String[] s = both.array();
Antwoord 11, autoriteit 2%
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));
both.toArray(new String[0]);
Antwoord 12, autoriteit 2%
Een andere manier met Java8 met Stream
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);
}
Antwoord 13
Hier is een aanpassing van de oplossing van silvertab, met achteraf aangebrachte generieke geneesmiddelen:
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;
}
OPMERKING: zie Joachims antwoordvoor een Java 6-oplossing. Het elimineert niet alleen de waarschuwing; het is ook korter, efficiënter en gemakkelijker te lezen!
Antwoord 14
Je zou kunnen proberen het te converteren naar een Arraylist en de addAll-methode te gebruiken en vervolgens terug te converteren naar een array.
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
Antwoord 15
Als je deze manier gebruikt, hoef je geen klasse van derden te importeren.
Als u String
wilt samenvoegen
Voorbeeldcode voor het samenvoegen van twee String Array
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;
}
Als u Int
wilt samenvoegen
Voorbeeldcode voor het samenvoegen van twee Integer-arrays
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;
}
Hier is de hoofdmethode
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));
}
}
We kunnen op deze manier ook gebruiken.
Antwoord 16
Vergeef me alsjeblieft voor het toevoegen van nog een andere versie aan deze al lange lijst. Ik keek naar elk antwoord en besloot dat ik echt een versie wilde met slechts één parameter in de handtekening. Ik heb ook een aantal argumentencontrole toegevoegd om te profiteren van vroege mislukking met verstandige informatie in geval van onverwachte invoer.
@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;
}
Antwoord 17
Met Java 8+ streams kun je de volgende functie schrijven:
private static String[] concatArrays(final String[]... arrays) {
return Arrays.stream(arrays)
.flatMap(Arrays::stream)
.toArray(String[]::new);
}
Antwoord 18
Hier een mogelijke implementatie in werkende code van de pseudo-code-oplossing geschreven door silvertab.
Bedankt 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;
}
}
Hierna volgt de bouwer-interface.
Opmerking: een builder is nodig omdat het in Java niet mogelijk is om
new T[size]
vanwege het wissen van het algemene type:
public interface ArrayBuilderI<T> {
public T[] build(int size);
}
Hier een concrete bouwer die de interface implementeert en een Integer
array bouwt:
public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {
@Override
public Integer[] build(int size) {
return new Integer[size];
}
}
en ten slotte de toepassing / test:
@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]);
}
}
Antwoord 19
Dit zou een voering moeten zijn.
public String [] concatenate (final String array1[], final String array2[])
{
return Stream.concat(Stream.of(array1), Stream.of(array2)).toArray(String[]::new);
}
Antwoord 20
WOW! Veel complexe antwoorden hier inclusief enkele eenvoudige die afhankelijk zijn van externe afhankelijkheden. Hoe zit het met het doen als dit:
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]);
Antwoord 21
Dit werkt, maar u moet uw eigen foutcontrole invoegen.
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();
}
}
Het is waarschijnlijk niet de meest efficiënte, maar het is niet afhankelijk van iets anders dan Java’s eigen API.
Antwoord 22
Dit is een geconverteerde functie voor een String-array:
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;
}
Antwoord 23
Wat dacht je van gewoon
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());
}
}
En doe gewoon Array.concat(arr1, arr2)
. Zolang arr1
en arr2
van hetzelfde type zijn, krijg je een andere array van hetzelfde type die beide arrays bevat.
Antwoord 24
Een eenvoudige variatie die het samenvoegen van meer dan één array mogelijk maakt:
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()]);
}
Antwoord 25
Een generieke statische versie die gebruikmaakt van de goed presterende System.arraycopy zonder een @SuppressWarnings-annotatie:
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;
}
Antwoord 26
Alleen Java’s eigen API gebruiken:
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]);
}
Deze code is niet de meest efficiënte, maar hij vertrouwt alleen op standaard Java-klassen en is gemakkelijk te begrijpen. Het werkt voor elk aantal String[] (zelfs nul arrays).
Antwoord 27
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;
}
Antwoord 28
Hier is mijn enigszins verbeterde versie van Joachim Sauer’s Concatall. Het kan werken op Java 5 of 6, met behulp van Java 6’s System.arraycopy als het op runtime beschikbaar is. Deze methode (IMHO) is perfect voor Android, omdat het op Android & LT; 9 werkt (wat geen System.arraycopy) heeft, maar de snellere methode gebruikt indien mogelijk.
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;
}
Antwoord 29
Een andere manier om over de vraag na te denken. Om twee of meer arrays samen te voegen, hoef je alleen maar alle elementen van elke array op te sommen en vervolgens een nieuwe array te bouwen. Dit klinkt als een List<T>
maken en er vervolgens toArray
op aanroepen. Sommige andere antwoorden gebruiken ArrayList
, en dat is prima. Maar hoe zit het met het implementeren van onze eigen? Het is niet moeilijk:
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);
}
Ik geloof dat het bovenstaande equivalent is aan oplossingen die System.arraycopy
gebruiken. Maar ik denk dat deze zijn eigen schoonheid heeft.
Antwoord 30
Wat dacht je van:
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()]);
}