Comment concaténer deux tableaux en Java?
je dois concaténer deux tableaux de chaîne en Java.
void f(String[] first, String[] second) {
String[] both = ???
}
Quelle est la meilleure façon de le faire?
30 réponses
j'ai trouvé une solution à une ligne de la bonne vieille bibliothèque Lang Apache Commons.
ArrayUtils.addAll(T[], T...)
Code:
String[] both = (String[])ArrayUtils.addAll(first, second);
Voici une méthode simple qui concaténera deux tableaux et retournera le résultat:
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;
}
Note Comme si cela ne fonctionnait pas avec les primitives, seulement avec les types d'objets.
la version suivante un peu plus compliquée fonctionne à la fois avec des tableaux objet et primitifs. Il le fait en utilisant T
au lieu de T[]
comme type d'argument.
il permet également de concaténer des matrices de deux différents types En choisissant le type le plus général comme type de composant du résultat.
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;
}
voici un exemple:
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 }));
il est possible d'écrire une version entièrement générique qui peut même être étendue pour concaténer n'importe quel nombre de tableaux. Cette version nécessite Java 6, car ils utilisent Arrays.copyOf()
les deux versions évitent de créer des objets intermédiaires List
et utilisent System.arraycopy()
pour s'assurer que la copie de grands tableaux est aussi rapide que possible.
pour deux tableaux il ressemble à ceci:
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;
}
et pour nombre arbitraire de tableaux (>= 1), il ressemble à ceci:
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;
}
One-liner en Java 8:
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);
ou:
String[] both = Stream.of(a, b).flatMap(Stream::of)
.toArray(String[]::new);
ou avec le bien-aimé Goyave :
String[] both = ObjectArrays.concat(first, second, String.class);
il existe aussi des versions pour les tableaux primitifs:
-
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)
utilisant L'API Java:
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()]);
}
System.arraycopy
(non disponible dans GWT client par exemple):
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;
}
j'ai récemment combattu des problèmes de rotation excessive de la mémoire. Si l'on sait que a et/ou b sont généralement vides, voici une autre adaptation du code de silvertab (générifié aussi):
private static <T> T[] concat(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;
}
(dans les deux cas, le comportement de réutilisation du tableau doit être clairement Javadocisé!)
la bibliothèque Java fonctionnel a une classe d'enrubannage de tableau qui fournit des tableaux avec des méthodes pratiques comme la concaténation.
import static fj.data.Array.array;
...et puis
Array<String> both = array(first).append(array(second));
pour obtenir le tableau non emballé de retour, appelez
String[] s = both.array();
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));
both.toArray(new String[0]);
Vous pouvez ajouter les deux tableaux en deux lignes de code.
String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);
C'est une solution rapide et efficace et de travail pour les types primitifs, ainsi que les deux méthodes sont surchargées.
vous devez éviter les solutions impliquant des ArrayLists, des flux, etc car ceux-ci auront besoin d'allouer la mémoire temporaire sans but utile.
vous devez éviter les boucles for
car elles ne sont pas efficaces. Construit dans le les méthodes utilisent des fonctions de copie de bloc qui sont extrêmement rapides.
voici une adaptation de la solution de silvertab, avec generics Retrofited:
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;
}
NOTE: voir réponse de Joachim pour une solution Java 6. Non seulement il élimine l'avertissement, mais il est aussi plus court, plus efficace et plus facile à lire!
une autre façon avec Java8 en utilisant 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);
}
si vous utilisez cette façon de sorte que vous n'avez pas besoin d'importer une classe de tiers.
si vous voulez concaténate String
Exemple de code pour concate deux Tableau de Chaîne
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;
}
si vous voulez concaténate Int
Exemple de code pour concate deux Tableau d'Entiers
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;
}
Voici la méthode principale
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));
}
}
nous pouvons utiliser cette façon aussi.
s'il vous plaît pardonnez-moi d'ajouter une autre version à cette liste déjà longue. J'ai regardé chaque réponse et j'ai décidé que je voulais vraiment une version avec un seul paramètre dans la signature. J'ai également ajouté une vérification des arguments pour bénéficier de l'échec précoce avec des informations sensées en cas d'entrée inattendue.
@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;
}
vous pouvez essayer de le convertir en un Arraylist et utiliser la méthode addAll puis convertir de nouveau en un tableau.
List list = new ArrayList(Arrays.asList(first));
list.addAll(Arrays.asList(second));
String[] both = list.toArray();
ici une implémentation possible en code de travail de la solution pseudo code écrite par silvertab.
Merci 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;
}
}
suit ensuite l'interface builder.
Note: un builder est nécessaire car en java il n'est pas possible de faire
new T[size]
dû au type générique erasure:
public interface ArrayBuilderI<T> {
public T[] build(int size);
}
voici un béton constructeur mettant en œuvre l'interface, la construction d'un Integer
tableau:
public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {
@Override
public Integer[] build(int size) {
return new Integer[size];
}
}
et enfin l'application / essai:
@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]);
}
}
Wow! beaucoup de réponses complexes ici, y compris quelques réponses simples qui dépendent de dépendances externes. Que diriez-vous de le faire comme ceci:
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]);
il s'agit d'une fonction convertie pour un tableau de chaînes de caractères:
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;
}
Que Diriez-vous simplement
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());
}
}
Et il suffit de faire Array.concat(arr1, arr2)
. Tant que arr1
et arr2
sont du même type, cela vous donnera un autre tableau du même type contenant les deux tableaux.
Cela fonctionne, mais vous devez insérer votre propre vérification d'erreur.
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();
}
}
Ce n'est probablement pas le plus efficace, mais il ne s'appuie sur rien d'autre que la propre API Java.
voici ma version légèrement améliorée du concatAll de Joachim Sauer. Il peut fonctionner sur Java 5 ou 6, en utilisant le système de Java 6.arraycopy si elle est disponible à l'exécution. Cette méthode (IMHO) est parfaite pour Android, car il fonctionne sur Android <9 (qui n'a pas de système.arraycopy) mais utilisera la méthode plus rapide si possible.
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;
}
une autre façon de penser à la question. Pour concaténer deux ou plusieurs tableaux, il faut faire la liste de tous les éléments de chaque tableau, puis construire un nouveau tableau. Cela ressemble à créer un List<T>
et appelle ensuite toArray
. D'autres réponses utilisent ArrayList
, et c'est très bien. Mais comment mettre en œuvre notre propre? Il n'est pas difficile:
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);
}
je crois que ce qui précède est équivalent à des solutions qui utilisent System.arraycopy
. Cependant, je pense que ce qu'on a sa propre beauté.
Que Diriez-vous de:
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()]);
}
variation simple permettant l'assemblage de plusieurs réseaux:
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()]);
}
utilisant uniquement L'API Javas own:
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]);
}
maintenant, ce code n'est pas le plus efficace, mais il s'appuie uniquement sur les classes java standard et est facile à comprendre. Il fonctionne pour n'importe quel nombre de chaîne[] (même zéro tableaux).
une façon facile, mais inefficace, de le faire (génériques non inclus):
ArrayList baseArray = new ArrayList(Arrays.asList(array1));
baseArray.addAll(Arrays.asList(array2));
String concatenated[] = (String []) baseArray.toArray(new String[baseArray.size()]);
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;
}
String [] both = new ArrayList<String>(){{addAll(Arrays.asList(first)); addAll(Arrays.asList(second));}}.toArray(new String[0]);
Un type indépendant de la variation (mis à JOUR grâce à la Volée pour l'instanciation T):
@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()));
}