Làm thế nào tôi có thể nối hai mảng trong Java?


1366

Tôi cần nối hai Stringmảng trong Java.

void f(String[] first, String[] second) {
    String[] both = ???
}

cách dễ nhất để làm điều này là gì?


3
Bytes.concat từ Guava
Ben Trang

1
Tôi thấy rất nhiều câu trả lời ở đây nhưng câu hỏi rất hay ('cách dễ nhất'?) Đến nỗi nó không cho phép trả lời tốt nhất ...
Artur Opalinski

2
Hàng tá câu trả lời ở đây đang sao chép dữ liệu vào một mảng mới bởi vì đó là những gì được yêu cầu - nhưng sao chép dữ liệu khi không thực sự cần thiết là một điều tồi tệ phải làm đặc biệt là trong Java. Thay vào đó, hãy theo dõi các chỉ mục và sử dụng hai mảng như thể chúng được nối. Tôi đã thêm một giải pháp minh họa kỹ thuật.
Douglas Held

12
Việc một câu hỏi như thế này hiện có 50 câu trả lời khác nhau khiến tôi tự hỏi tại sao Java không bao giờ có một cách array1 + array2ghép đơn giản .
JollyJoker

2
Bạn có thể làm điều đó một cách hoàn hảo và rất hiệu quả trong hai dòng Java tiêu chuẩn (xem câu trả lời của tôi), vì vậy không có gì nhiều để đạt được bằng cách có một phương pháp duy nhất để làm điều đó. Tất cả những giải pháp kỳ lạ và tuyệt vời này là một chút lãng phí thời gian.
rghome

Câu trả lời:


1093

Tôi đã tìm thấy một giải pháp một dòng từ thư viện Apache Commons Lang cũ.
ArrayUtils.addAll(T[], T...)

Mã số:

String[] both = ArrayUtils.addAll(first, second);

175
Làm thế nào là "gian lận" nếu nó trả lời câu hỏi? Chắc chắn, có một sự phụ thuộc thêm có lẽ là quá mức cần thiết cho tình huống cụ thể này, nhưng không có hại gì khi gọi nó tồn tại, đặc biệt là vì có rất nhiều chức năng tuyệt vời trong Apache Commons.
Cướp

33
Tôi đồng ý, đây không thực sự trả lời câu hỏi. Thư viện cấp cao có thể rất tuyệt, nhưng nếu bạn muốn tìm hiểu một cách hiệu quả để làm điều đó, bạn muốn xem mã mà phương thức thư viện đang sử dụng. Ngoài ra, trong nhiều tình huống, bạn không thể đi qua một thư viện khác trong sản phẩm một cách nhanh chóng.
AdamC

76
Tôi nghĩ rằng đây là một câu trả lời tốt. Các giải pháp POJO cũng đã được cung cấp, nhưng nếu OP đang sử dụng Apache Commons trong chương trình của họ (hoàn toàn có thể xem xét mức độ phổ biến của nó), anh ta vẫn có thể không biết giải pháp này. Sau đó, anh ta sẽ không "thêm một phụ thuộc cho một phương thức này", nhưng sẽ sử dụng tốt hơn một thư viện hiện có.
Adam

14
Nếu bạn luôn lo lắng về việc không thêm thư viện cho một phương thức, sẽ không có thư viện mới nào được thêm vào. Với các tiện ích tuyệt vời có trong Apache Commons, tôi đặc biệt khuyên bạn nên thêm nó khi trường hợp sử dụng đầu tiên phát sinh.
Hindol

6
sử dụng apache commons không bao giờ nên được gọi là 'gian lận', tôi nghi ngờ sự tỉnh táo của các nhà phát triển, những người coi đó là một sự phụ thuộc không cần thiết.
Jeryl Cook

768

Đây là một phương pháp đơn giản sẽ ghép hai mảng và trả về kết quả:

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

Lưu ý rằng nó sẽ không hoạt động với các kiểu dữ liệu nguyên thủy, chỉ với các kiểu đối tượng.

Phiên bản phức tạp hơn một chút sau đây hoạt động với cả mảng đối tượng và mảng nguyên thủy. Nó thực hiện điều này bằng cách sử dụng Tthay vì T[]làm kiểu đối số.

Nó cũng cho phép ghép các mảng của hai loại khác nhau bằng cách chọn loại chung nhất làm loại thành phần của kết quả.

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

Đây là một ví dụ:

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
Tôi thích đề xuất này vì nó ít phụ thuộc vào các phiên bản Java mới nhất. Trong các dự án của tôi, tôi thường bị mắc kẹt khi sử dụng các phiên bản cũ hơn của các cấu hình Java hoặc CLDC trong đó một số phương tiện như Antti đã đề cập không có sẵn.
kvn

4
Dòng sau sẽ phá vỡ phần chung: concatenate (new String [] {"1"}, new Object [] {new Object ()})
dragon66

sẽ rất tuyệt nếu không phải sử dụng chú thích @SuppressWarnings - Tôi sẽ đăng một giải pháp cho điều đó bên dưới.
đèn hiệu

+1 cho Array.newInstance(a.getClass().getComponentType(), aLen + bLen);. Tôi đã ngạc nhiên chưa bao giờ thấy điều đó trước đây. @beaudet Tôi nghĩ rằng chú thích ở đây là tốt, xem xét lý do tại sao nó bị đàn áp.
Blake

1
ha, gọi tôi là người theo chủ nghĩa thuần túy nhưng tôi thích mã sạch không yêu cầu ngăn chặn các cảnh báo để xóa cảnh báo
beaudet

475

Có thể viết một phiên bản hoàn toàn chung thậm chí có thể được mở rộng để nối bất kỳ số lượng mảng nào. Các phiên bản này yêu cầu Java 6, vì chúng sử dụngArrays.copyOf()

Cả hai phiên bản đều tránh tạo ra bất kỳ Listđối tượng trung gian nào và sử dụng System.arraycopy()để đảm bảo rằng sao chép các mảng lớn càng nhanh càng tốt.

Đối với hai mảng, nó trông như thế này:

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

Và đối với số lượng mảng tùy ý (> = 1), nó trông như thế này:

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

10
@djBO: đối với các mảng được nhập nguyên thủy, bạn cần tạo quá tải cho từng loại: chỉ cần sao chép mã và thay thế từng mảng Tbằng byte(và mất <T>).
Joachim Sauer

bạn có thể cho tôi biết cách sử dụng loại toán tử <T> trong lớp của tôi không?
Johnydep

6
Tôi sẽ thêm điều này vào đầu, chỉ để phòng thủ. if (First == null) {if (second == null) {return null; } trở lại thứ hai; } if (second == null) {trả về trước; }
marathon

4
@djBo: những gì về:ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
Sam Goldberg

18
Có một lỗi trong cách tiếp cận này mà trở nên rõ ràng nếu bạn gọi các chức năng này với mảng của các loại thành phần khác nhau, ví dụ concat(ai, ad), nơi aiInteger[]adDouble[]. (Trong trường hợp này, tham số loại <T>được giải quyết <? extends Number>bởi trình biên dịch.) Mảng được tạo bởi Arrays.copyOfsẽ có kiểu thành phần của mảng đầu tiên, tức là Integertrong ví dụ này. Khi chức năng sắp sao chép mảng thứ hai, một ArrayStoreExceptionsẽ được ném. Giải pháp là có thêm một Class<T> typetham số.
T-Bull

457

Sử dụng Streamtrong Java 8:

String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
                      .toArray(String[]::new);

Hoặc như thế này, sử dụng flatMap:

String[] both = Stream.of(a, b).flatMap(Stream::of)
                      .toArray(String[]::new);

Để làm điều này cho một loại chung, bạn phải sử dụng sự phản chiếu:

@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
    size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));

28
Làm thế nào là hiệu quả này?
Supuhstar

8
Đáng đọc: jaxenter.com/... ; - (? Không phải là này lúc nào cũng là câu trả lời lol) tl dr suối có thể là performant hay không, nó phụ thuộc vào những gì bạn đang làm với họ và những hạn chế của vấn đề
Trevor Brown

6
Ngoài ra, nếu a hoặc b là mảng của các kiểu nguyên thủy, các luồng của chúng sẽ cần phải có kiểu .boxed()như vậy Streamchứ không phải là ví dụ IntStreamkhông thể được truyền dưới dạng tham số Stream.concat.
Will Hardwick-Smith

17
@Will Hardwick-Smith: không, bạn chỉ phải chọn đúng lớp stream, ví dụ: nếu abđang int[], sử dụngint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
Holger

3
@Supuhstar: Có lẽ không nhanh bằng System.arrayCopy. Nhưng cũng không đặc biệt chậm. Bạn có thể phải làm điều này rất nhiều lần với các mảng lớn trong các bối cảnh thực sự nhạy cảm về hiệu suất cho sự khác biệt về thời gian thực hiện.
Lii

191

Hoặc với quả ổi yêu quý :

String[] both = ObjectArrays.concat(first, second, String.class);

Ngoài ra, có các phiên bản cho mảng nguyên thủy:

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

Tôi yêu Guava rất nhiều, phương pháp từ Apache Commons xử lý tốt hơn với nullables.
Ravi Wallau

7
Mặc dù sử dụng các thư viện là tốt, nhưng thật không may là vấn đề đã được trừu tượng hóa. Do đó, giải pháp cơ bản vẫn khó nắm bắt.
user924272

51
Có vấn đề gì với sự trừu tượng? Không có thỏa thuận nào với việc phát minh lại bánh xe ở đây, nếu bạn muốn tìm hiểu vấn đề, hãy kiểm tra nguồn hoặc đọc trên đó. Mã chuyên nghiệp nên sử dụng các thư viện cấp cao, tốt hơn nhiều nếu được phát triển bên trong Google!
Breno Salgado

@RaviWallau Bạn có thể liên kết với lớp thực hiện điều này không?
Sébastien Tromp

1
@ SébastienTromp Đây là giải pháp hàng đầu cho câu hỏi này - ArrayUtils.
Ravi Wallau

70

Bạn có thể nối hai mảng trong hai dòng mã.

String[] both = Arrays.copyOf(first, first.length + second.length);
System.arraycopy(second, 0, both, first.length, second.length);

Đây là một giải pháp nhanh chóng và hiệu quả và sẽ hoạt động cho các loại nguyên thủy cũng như hai phương pháp liên quan bị quá tải.

Bạn nên tránh các giải pháp liên quan đến ArrayLists, luồng, v.v. vì những giải pháp này sẽ cần phân bổ bộ nhớ tạm thời cho mục đích hữu ích.

Bạn nên tránh forcác vòng lặp cho các mảng lớn vì chúng không hiệu quả. Các phương thức tích hợp sử dụng các hàm sao chép khối cực kỳ nhanh.


1
Đây là một trong những giải pháp tốt nhất. 100% Java tiêu chuẩn. Nhanh chóng / hiệu quả. Nên nhận thêm upvote!
Shebla Tsama

58

Sử dụng 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()]);
}

13
Đơn giản, nhưng không hiệu quả vì nó tạo một mảng cho ArrayList và sau đó tạo một mảng khác cho phương thức toArray. Nhưng vẫn hợp lệ vì nó đơn giản để đọc.
PhoneixS

1
áp dụng cho Chuỗi và đối tượng (như câu hỏi muốn), nhưng không có phương thức addAll cho các loại chính (dưới dạng int)
joro

Như được trình bày chi tiết trong bài viết này , việc sử dụng both.toArray(new String[0])sẽ nhanh hơn both.toArray(new String[both.size()]), ngay cả khi nó mâu thuẫn với trực giác ngây thơ của chúng ta. Đó là lý do tại sao nó rất quan trọng để đo hiệu suất thực tế khi tối ưu hóa. Hoặc chỉ sử dụng cấu trúc đơn giản hơn, khi không thể chứng minh được lợi thế của biến thể phức tạp hơn.
Holger

42

Một giải pháp java cũ 100%không có System.arraycopy (chẳng hạn trong ứng dụng khách 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;
}

làm lại của tôi cho File [], nhưng nó giống nhau. Cảm ơn giải pháp của bạn
ShadowFlame

5
Có lẽ khá không hiệu quả mặc dù.
JonasCz - Phục hồi lại

Bạn có thể muốn thêm nullséc. Và có lẽ đặt một số biến của bạn thành final.
Động học Tripp

nullKiểm tra @TrippKinetic sẽ ẩn NPE thay vì hiển thị chúng và sử dụng cuối cùng cho các vars cục bộ không có bất kỳ lợi ích nào (chưa).
Maarten Bodewes 24/03/19

1
@Maarten Bodewes Tôi nghĩ rằng bạn sẽ tìm thấy (nếu bạn điểm chuẩn nó, cái mà tôi có) rằng mỗi cái chạy cùng lúc với vòng lặp được lập chỉ mục trên các phiên bản cuối của Java. Trình tối ưu hóa chăm sóc nó.
rghome

33

Gần đây tôi đã chiến đấu với các vấn đề với vòng quay bộ nhớ quá mức. Nếu a và / hoặc b được biết là thường trống, thì đây là một sự thích ứng khác của mã silvertab (cũng được khái quát hóa):

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

Chỉnh sửa: Một phiên bản trước của bài đăng này đã tuyên bố rằng việc sử dụng lại mảng như thế này sẽ được ghi lại rõ ràng. Như Maarten chỉ ra trong các ý kiến, nói chung sẽ tốt hơn nếu chỉ loại bỏ các câu lệnh if, do đó làm mất đi sự cần thiết phải có tài liệu. Nhưng sau đó, một lần nữa, những tuyên bố nếu là toàn bộ điểm tối ưu hóa đặc biệt này ở nơi đầu tiên. Tôi sẽ để câu trả lời này ở đây, nhưng hãy cảnh giác!


5
tuy nhiên điều này có nghĩa là bạn đang trả về cùng một mảng và việc thay đổi một giá trị trên mảng được trả về sẽ thay đổi giá trị ở cùng vị trí của mảng đầu vào được trả về.
Lorenzo Boccaccia

Có - xem bình luận ở cuối bài viết của tôi về việc sử dụng lại mảng. Chi phí bảo trì áp đặt bởi giải pháp này đáng giá trong trường hợp cụ thể của chúng tôi, nhưng sao chép phòng thủ có lẽ nên được sử dụng trong hầu hết các trường hợp.
bóng chuyền

Lorenzo / bóng chuyền, bạn có thể giải thích phần nào trong mã gây ra việc sử dụng lại mảng không? Tôi nghĩ System.arraycopysao chép nội dung của mảng?
Rosdi Kasim

4
Một người gọi thường mong đợi một cuộc gọi đến concat () để trả về một mảng mới được phân bổ. Nếu a hoặc b là null, tuy nhiên concat () sẽ trả về một trong các mảng được truyền vào nó. Việc sử dụng lại này là những gì có thể bất ngờ. (Đúng, bản sao chỉ sao chép. Việc sử dụng lại xuất phát từ việc trả lại trực tiếp a hoặc b.)
bóng chuyền

Mã nên tự giải thích càng nhiều càng tốt. Mọi người đọc mã không cần phải tra cứu JavaDoc của một hàm được gọi để tìm ra rằng nó thực hiện một điều cho một điều kiện cụ thể và một điều khác cho một điều kiện khác. Tóm lại: bạn thường không thể khắc phục các sự cố thiết kế như thế này bằng một nhận xét. Chỉ cần để lại hai iftuyên bố sẽ là cách khắc phục dễ dàng nhất.
Maarten Bodewes 18/03/19

27

Các Java chức năng thư viện có một lớp wrapper mảng trang bị cho mảng với các phương pháp tiện dụng như nối.

import static fj.data.Array.array;

...và sau đó

Array<String> both = array(first).append(array(second));

Để lấy lại mảng chưa mở, hãy gọi

String[] s = both.array();

27
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));

both.toArray(new String[0]);

3
Câu trả lời là tuyệt vời nhưng một chút vỡ nhỏ. Để làm cho nó hoàn hảo, bạn nên chuyển đến toArray () một mảng của loại bạn cần. Trong ví dụ trên, mã phải là: cả.toArray (Chuỗi mới [0]) Xem: stackoverflow.com/questions/4042434/
Kẻ

Không biết tại sao câu trả lời này không được đánh giá cao hơn ... mặc dù có vẻ như cần thay đổi được đề xuất bởi @RonenRabinovici
drmrbrewer

4
Hoặc tốt hơn, không cần phân bổ mảng có độ dài bằng không : both.toArray(new String[both.size()]);)
Honza


Xin chào @Honza, có thể làm tương tự để trả về một mảng nguyên nguyên trong 3 dòng không?
jump_monkey

18

Một cách khác với Java8 bằng cách sử dụng 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); 
  }

17

Đây là bản phóng tác của giải pháp silvertab, với thuốc generic được trang bị thêm:

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

LƯU Ý: Xem câu trả lời của Joachim cho giải pháp Java 6. Nó không chỉ loại bỏ cảnh báo; Nó cũng ngắn hơn, hiệu quả hơn và dễ đọc hơn!


Bạn có thể loại bỏ cảnh báo cho phương pháp này, nhưng khác hơn là bạn không thể làm được gì nhiều. Mảng và thuốc generic không thực sự trộn lẫn.
Dan Dyer

3
Cảnh báo không được kiểm tra có thể được loại bỏ nếu bạn sử dụng Arrays.copyOf (). Xem câu trả lời của tôi để thực hiện.
Joachim Sauer

@SuppressWarnings ("không được kiểm tra")
Mark Renouf

13

Nếu bạn sử dụng cách này để bạn không cần phải nhập bất kỳ lớp bên thứ ba nào.

Nếu bạn muốn nối String

Mã mẫu để nối hai chuỗi 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;
    }

Nếu bạn muốn nối Int

Mã mẫu để nối hai mảng Integer

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

Đây là phương pháp chính

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

        }
    }  

Chúng ta cũng có thể sử dụng cách này.


11

Xin vui lòng tha thứ cho tôi vì đã thêm một phiên bản khác vào danh sách đã dài này. Tôi đã xem xét mọi câu trả lời và quyết định rằng tôi thực sự muốn có một phiên bản chỉ có một tham số trong chữ ký. Tôi cũng đã thêm một số kiểm tra đối số để hưởng lợi từ thất bại sớm với thông tin hợp lý trong trường hợp đầu vào bất ngờ.

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

Tôi sẽ tổng hợp độ dài trong cùng một vòng lặp nơi bạn đang thực hiện kiểm tra null - nhưng đây là một bản tóm tắt thực sự tốt về các câu trả lời khác ở đây. Tôi tin rằng nó thậm chí còn xử lý các loại nội tại như "int" mà không thay đổi chúng thành các đối tượng Integer, đây thực sự là lý do DUY NHẤT để xử lý chúng dưới dạng mảng thay vì chỉ thay đổi mọi thứ thành ArrayLists. Ngoài ra phương thức của bạn có thể mất 2 mảng và tham số (...) để người gọi biết rằng anh ta cần phải vượt qua ít nhất hai mảng trước khi chạy và thấy lỗi, nhưng điều đó làm phức tạp mã vòng lặp ....
Bill K

11

Bạn có thể thử chuyển đổi nó thành một Arraylist và sử dụng phương thức addAll sau đó chuyển đổi trở lại thành một mảng.

List list = new ArrayList(Arrays.asList(first));
  list.addAll(Arrays.asList(second));
  String[] both = list.toArray();

Giải pháp tốt - sẽ tốt hơn nếu mã được tái cấu trúc để tránh các mảng hoàn toàn có lợi cho ArrayLists, nhưng điều đó nằm ngoài tầm kiểm soát của "Trả lời" và cho người hỏi.
Bill K

Tôi đếm rằng nó cần thêm 4 đối tượng tạm thời để làm việc.
rghome

@rghome, ít nhất nó không yêu cầu thư viện bổ sung để thực hiện nhiệm vụ đơn giản như vậy
Farid

9

Sử dụng luồng Java 8+, bạn có thể viết hàm sau:

private static String[] concatArrays(final String[]... arrays) {
    return Arrays.stream(arrays)
         .flatMap(Arrays::stream)
         .toArray(String[]::new);
}

7

Đây là một triển khai có thể có trong mã làm việc của giải pháp mã giả được viết bởi silvertab.

Cảm ơn 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;
   }
}

Tiếp theo là giao diện xây dựng.

Lưu ý: Trình xây dựng là cần thiết vì trong java không thể thực hiện được

new T[size]

do loại chung chung xóa:

public interface ArrayBuilderI<T> {

   public T[] build(int size);
}

Ở đây một người xây dựng cụ thể thực hiện giao diện, xây dựng một Integermảng:

public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {

   @Override
   public Integer[] build(int size) {
      return new Integer[size];
   }
}

Và cuối cùng là ứng dụng / kiểm tra:

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

7

Điều này nên là một lót.

public String [] concatenate (final String array1[], final String array2[])
{
    return Stream.concat(Stream.of(array1), Stream.of(array2)).toArray(String[]::new);
}

6

Ồ rất nhiều câu trả lời phức tạp ở đây bao gồm một số câu trả lời đơn giản phụ thuộc vào sự phụ thuộc bên ngoài. làm thế nào để làm điều đó như thế này:

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

1
..Nhưng không hiệu quả và chậm.
JonasCz - Tái lập Monica

6

Điều này hoạt động, nhưng bạn cần chèn kiểm tra lỗi của riêng bạn.

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

Đây có thể không phải là hiệu quả nhất, nhưng nó không dựa vào bất cứ thứ gì ngoài API riêng của Java.


2
+1. Sẽ tốt hơn nếu thay thế forvòng lặp thứ hai bằng cách đó:for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
bancer

Sử dụng String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)để bỏ qua forvòng lặp đầu tiên . Tiết kiệm thời gian tỷ lệ thuận với kích thước của arr1.
John Meyer

5

Đây là một hàm được chuyển đổi cho một mảng 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;
}

5

Đơn giản thế nào

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

Và chỉ cần làm Array.concat(arr1, arr2). Miễn là arr1arr2cùng loại, điều này sẽ cung cấp cho bạn một mảng khác cùng loại chứa cả hai mảng.


Vì lý do hiệu năng, tôi sẽ tính toán trước kích thước cuối cùng của ArrayList vì theo định nghĩa, ArrayList phân bổ một mảng mới và sao chép các phần tử của nó mỗi khi mảng hiện tại đầy. Nếu không, tôi sẽ đi thẳng vào LinkedList mà không gặp phải vấn đề như vậy
usr-local-ΕΨΗΕΛΩΝ 20/8/2015

5

Một phiên bản tĩnh chung sử dụng System.arraycopy hiệu suất cao mà không yêu cầu chú thích @SuppressWarnings:

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

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

4

Đây là phiên bản cải tiến của Joachimerer của tôi. Nó có thể hoạt động trên Java 5 hoặc 6, sử dụng System.arraycopy của Java 6 nếu nó có sẵn trong thời gian chạy. Phương pháp này (IMHO) hoàn hảo cho Android, vì nó hoạt động trên Android <9 (không có System.arraycopy) nhưng sẽ sử dụng phương pháp nhanh hơn nếu có thể.

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

1
Ý tưởng chung tốt, nhưng với bất kỳ ai thực hiện: Tôi thích phiên bản copyOf và không copyOf hơn phiên bản phản ánh cả hai.
rektide

4

Một cách khác để suy nghĩ về câu hỏi. Để nối hai hoặc nhiều mảng, người ta phải làm là liệt kê tất cả các phần tử của mỗi mảng, sau đó xây dựng một mảng mới. Điều này âm thanh như tạo ra một List<T>và sau đó gọi toArraynó. Một số câu trả lời khác sử dụng ArrayList, và điều đó tốt. Nhưng làm thế nào về việc thực hiện của chúng ta? Nó không khó:

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

Tôi tin rằng ở trên là tương đương với các giải pháp sử dụng System.arraycopy. Tuy nhiên tôi nghĩ cái này có vẻ đẹp riêng của nó.


4

Làm thế nào về :

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

4

Một biến thể đơn giản cho phép nối nhiều hơn một mảng:

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

3

Chỉ sử dụng API riêng của Javas:


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

Bây giờ, mã này không phải là hiệu quả nhất, nhưng nó chỉ dựa trên các lớp java tiêu chuẩn và rất dễ hiểu. Nó hoạt động với bất kỳ số lượng Chuỗi [] (thậm chí là không có mảng).


15
Phải downvote cái này cho tất cả việc tạo đối tượng List không cần thiết.
Lập trình viên ngoài vòng pháp luật
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.