J'ai besoin de concaténer deux String
tableaux en Java.
void f(String[] first, String[] second) {
String[] both = ???
}
Quel est le moyen le plus simple de le faire ?
J'ai besoin de concaténer deux String
tableaux en Java.
void f(String[] first, String[] second) {
String[] both = ???
}
Quel est le moyen le plus simple de le faire ?
J'ai trouvé une solution en une ligne dans la bonne vieille bibliothèque Apache Commons Lang.ArrayUtils.addAll(T[], T...)
Code :
String[] both = ArrayUtils.addAll(first, second);
En quoi est-ce une "tricherie" si elle répond à la question ? Bien sûr, avoir une dépendance supplémentaire est probablement exagéré pour cette situation spécifique, mais il n'y a aucun mal à signaler son existence, d'autant plus qu'il y a tant d'excellents éléments de fonctionnalité dans Apache Commons.
Je suis d'accord, ça ne répond pas vraiment à la question. Les bibliothèques de haut niveau peuvent être formidables, mais si vous voulez apprendre un moyen efficace de le faire, vous devez examiner le code que la méthode de la bibliothèque utilise. En outre, dans de nombreuses situations, vous ne pouvez pas simplement intégrer une autre bibliothèque dans le produit à la volée.
Je pense que c'est une bonne réponse. Des solutions POJO ont également été proposées, mais si le PO utilise déjà Apache Commons dans son programme (ce qui est tout à fait possible compte tenu de sa popularité), il ne connaît peut-être pas encore cette solution. Dans ce cas, il ne s'agirait pas d'ajouter une dépendance pour cette seule méthode, mais de faire un meilleur usage d'une bibliothèque existante.
Voici une méthode simple qui va concaténer deux tableaux et renvoyer 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;
}
Notez que cela ne fonctionnera pas avec les types de données primitifs, mais uniquement avec les types d'objets.
La version suivante, légèrement plus compliquée, fonctionne à la fois avec les tableaux d'objets et les tableaux primitifs. Pour ce faire, elle utilise T
au lieu de T[]
comme type d'argument.
Il permet également de concaténer des tableaux de deux types différents 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 }));
J'aime cette suggestion car elle est moins dépendante des dernières versions de Java. Dans mes projets, je suis souvent contraint d'utiliser des versions plus anciennes de Java ou des profils CLDC pour lesquels certaines fonctions, comme celles mentionnées par Antti, ne sont pas disponibles.
La ligne suivante va casser la partie générique : concatenate(new String[]{"1"},new Object[] { new Object()})
Ce serait bien de ne pas avoir à utiliser l'annotation @SuppressWarnings - je posterai une solution pour cela ci-dessous.
Utilisation de Stream
en Java 8 :
String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
.toArray(String[]::new);
Ou comme ceci, en utilisant flatMap
:
String[] both = Stream.of(a, b).flatMap(Stream::of)
.toArray(String[]::new);
Pour faire cela pour un type générique, vous devez utiliser la réflexion :
@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));
Cela vaut la peine de le lire : jaxenter.com/ tl;dr - les flux peuvent être performants ou non, cela dépend de ce que vous faites avec eux et des contraintes du problème (n'est-ce pas toujours la réponse ? lol).
Oui, c'est une solution risquée du point de vue des performances. Elle est peut-être rapide, mais je ne parierais pas sur les performances de mon application ;)
Il est possible d'écrire une version entièrement générique qui peut même être étendue pour concaténer un nombre quelconque de tableaux. Cette version nécessite Java 6, car elle utilise Arrays.copyOf()
Les deux versions évitent de créer tout intermédiaire List
les objets et l'utilisation System.arraycopy()
pour s'assurer que la copie de grands tableaux est aussi rapide que possible.
Pour deux tableaux, cela 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 un nombre arbitraire de tableaux (>= 1), cela 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;
}
@djBO : pour les tableaux à caractères primitifs, il faut créer une surcharge pour chaque type : il suffit de copier le code et de remplacer chaque type par un autre. T
con byte
(et perdre le <T>
).
J'ajouterais ceci au début, juste pour être sur la défensive. if (first == null) { if (second == null) { return null ; } return second ; } if (second == null) { return first ; }
Ou avec le bien-aimé Goyave :
String[] both = ObjectArrays.concat(first, second, String.class);
Il existe également 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)
Même si j'aime beaucoup Guava, la méthode d'Apache Commons est plus efficace avec les valeurs nulles.
S'il est bon d'utiliser des bibliothèques, il est regrettable que le problème ait été occulté. Par conséquent, la solution sous-jacente reste insaisissable.
Quel est le problème de l'abstraction ? Je ne comprends pas pourquoi il faut réinventer la roue ici, si vous voulez apprendre le problème, vérifiez la source ou lisez à ce sujet. Le code professionnel devrait utiliser des bibliothèques de haut niveau, bien mieux s'il est développé au sein de Google !
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
3 votes
Bytes.concat de Guava
1 votes
Je vois beaucoup de réponses ici mais la question est formulée de telle manière ('le plus simple' ?) qu'elle ne permet pas d'indiquer la meilleure réponse...
3 votes
Des dizaines de réponses ici copient les données dans un nouveau tableau parce que c'est ce qui a été demandé - mais copier des données quand ce n'est pas strictement nécessaire est une mauvaise chose à faire, surtout en Java. Au lieu de cela, gardez la trace des index et utilisez les deux tableaux comme s'ils étaient joints. J'ai ajouté une solution illustrant la technique.
1 votes
Le plus simple est que vous ne devriez probablement pas utiliser de tableaux en premier lieu, vous devriez utiliser des listes de tableaux, et votre sortie devrait être une liste de tableaux. Une fois que vous en avez fait votre condition préalable, l'opération est intégrée : first.addAll(second). Le seul cas où cela ne serait pas automatique est lorsque vos tableaux sont de types non-objets (int, long, double, ...), dans ce cas les tableaux intrinsèques peuvent avoir un grand avantage sur les ArrayLists - mais pour les chaînes de caractères, c'est non.
34 votes
Le fait qu'une question comme celle-ci ait actuellement 50 réponses différentes m'amène à me demander pourquoi Java n'a jamais eu de simple
array1 + array2
concaténation.2 votes
Vous pouvez le faire parfaitement et très efficacement en deux lignes de Java standard (voir ma réponse), donc il n'y a pas grand chose à gagner à avoir une seule méthode pour le faire. Toutes ces solutions bizarres et merveilleuses sont un peu une perte de temps.