1514 votes

Comment concaténer deux tableaux en Java ?

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 ?

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.

1220voto

Antti Sykäri Points 10381

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);

195 votes

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.

38 votes

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.

84 votes

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.

787voto

jeannicolas Points 2325

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 }));

1 votes

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.

4 votes

La ligne suivante va casser la partie générique : concatenate(new String[]{"1"},new Object[] { new Object()})

0 votes

Ce serait bien de ne pas avoir à utiliser l'annotation @SuppressWarnings - je posterai une solution pour cela ci-dessous.

547voto

Vitalii Fedorenko Points 17469

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));

36 votes

Quelle est l'efficacité de ce système ?

9 votes

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).

0 votes

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 ;)

491voto

Joachim Sauer Points 133411

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;
}

11 votes

@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> ).

0 votes

Pouvez-vous me dire comment utiliser l'opérateur <T> dans ma classe ?

6 votes

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 ; }

200voto

KARASZI István Points 15162

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)

0 votes

Même si j'aime beaucoup Guava, la méthode d'Apache Commons est plus efficace avec les valeurs nulles.

7 votes

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.

53 votes

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.com

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.

Powered by:

X