ฉันจะต่อสองอาร์เรย์ใน Java ได้อย่างไร


1366

ฉันต้องต่อสองStringอาร์เรย์ใน Java

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

วิธีที่ง่ายที่สุดในการทำเช่นนี้คืออะไร?


3
Bytes.concat จาก Guava
Ben Page

1
ฉันเห็นคำตอบมากมายที่นี่ แต่คำถามก็คือคำพูด ('วิธีที่ง่ายที่สุด'?) ที่ไม่อนุญาตให้ระบุคำตอบที่ดีที่สุด ...
Artur Opalinski

2
หลายสิบคำตอบที่นี่กำลังคัดลอกข้อมูลไปยังอาร์เรย์ใหม่เพราะนั่นคือสิ่งที่ถูกถาม - แต่การคัดลอกข้อมูลเมื่อไม่จำเป็นอย่างเคร่งครัดเป็นสิ่งที่ไม่ดีโดยเฉพาะอย่างยิ่งใน Java ติดตามดัชนีและใช้สองอาร์เรย์แทนหากเข้าร่วม ฉันได้เพิ่มวิธีแก้ปัญหาที่แสดงให้เห็นถึงเทคนิค
Douglas Held

12
ความจริงที่ว่าคำถามเช่นนี้ในปัจจุบันมี 50 คำตอบที่แตกต่างกันทำให้ฉันสงสัยว่าทำไม Java ไม่เคยมีการarray1 + array2เรียงต่อกันอย่างง่าย
JollyJoker

2
คุณสามารถทำได้อย่างสมบูรณ์แบบและมีประสิทธิภาพมากในสองบรรทัดของ Java มาตรฐาน (ดูคำตอบของฉัน) ดังนั้นจึงไม่มีอะไรที่น่ากลัวมากที่จะได้รับโดยมีวิธีการเดียวที่จะทำ โซลูชั่นที่แปลกประหลาดเหล่านี้ทั้งหมดใช้เวลาพอสมควร
rghome

คำตอบ:


1093

ฉันพบโซลูชันบรรทัดเดียวจากห้องสมุด Apache Commons Lang เก่าที่ดี
ArrayUtils.addAll(T[], T...)

รหัส:

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

175
"โกง" เป็นอย่างไรถ้าตอบคำถาม แน่นอนว่าการมีการพึ่งพาเป็นพิเศษอาจเกินความจำเป็นสำหรับสถานการณ์เฉพาะนี้ แต่ไม่มีอันตรายใด ๆ เกิดขึ้นในการเรียกว่ามีอยู่โดยเฉพาะอย่างยิ่งเนื่องจากมีฟังก์ชันการทำงานที่ยอดเยี่ยมมากมายใน Apache Commons
Rob

33
ฉันเห็นด้วยว่านี่ไม่ใช่การตอบคำถามจริงๆ ไลบรารีระดับสูงนั้นยอดเยี่ยม แต่ถ้าคุณต้องการเรียนรู้วิธีที่มีประสิทธิภาพในการทำคุณต้องการดูรหัสที่วิธีการใช้งานของไลบรารี ในหลาย ๆ สถานการณ์คุณไม่สามารถผ่านห้องสมุดอื่นในผลิตภัณฑ์ได้ทันที
AdamC

76
ฉันคิดว่านี่เป็นคำตอบที่ดี นอกจากนี้ยังมีการจัดเตรียมโซลูชัน POJO ด้วยเช่นกัน แต่ถ้า OP ใช้ Apache Commons ในโปรแกรมของพวกเขาอยู่แล้ว (อาจเป็นไปได้เมื่อพิจารณาถึงความนิยม) เขาอาจยังไม่รู้วิธีแก้ปัญหานี้ จากนั้นเขาจะไม่ "เพิ่มการพึ่งพาสำหรับวิธีนี้" แต่จะใช้ประโยชน์จากห้องสมุดที่มีอยู่ให้ดีขึ้น
Adam

14
หากคุณกังวลเกี่ยวกับการไม่เพิ่มห้องสมุดสำหรับวิธีการเดียวจะไม่มีการเพิ่มห้องสมุดใหม่เลย เมื่อพิจารณาถึงอรรถประโยชน์ที่ยอดเยี่ยมที่มีอยู่ใน Apache Commons ฉันขอแนะนำให้เพิ่มเมื่อมีการใช้งานครั้งแรก
Hindol

6
การใช้งาน apache ไม่ควรเรียกว่า 'การโกง' ฉันถามถึงความมีสติของนักพัฒนาที่พึ่งพาได้โดยไม่จำเป็น
Jeryl Cook

768

ต่อไปนี้เป็นวิธีการง่ายๆที่จะต่อกันสองอาร์เรย์และส่งคืนผลลัพธ์:

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

โปรดทราบว่ามันจะไม่ทำงานกับชนิดข้อมูลดั้งเดิมเท่านั้นกับประเภทวัตถุ

รุ่นที่ซับซ้อนมากขึ้นเล็กน้อยต่อไปนี้ใช้ได้กับทั้งออบเจ็กต์และอาร์เรย์ดั้งเดิม ทำได้โดยใช้TแทนT[]ประเภทอาร์กิวเมนต์

นอกจากนี้ยังทำให้สามารถเชื่อมต่ออาร์เรย์ของสองประเภทที่แตกต่างกันได้โดยเลือกประเภททั่วไปมากที่สุดเป็นประเภทส่วนประกอบของผลลัพธ์

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

นี่คือตัวอย่าง:

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
ฉันชอบคำแนะนำนี้เพราะมันขึ้นอยู่กับรุ่น Java ล่าสุดน้อยกว่า ในโครงการของฉันฉันมักจะติดอยู่กับรุ่นเก่าของ Java หรือ CLDC โปรไฟล์ที่สิ่งอำนวยความสะดวกบางอย่างเช่นที่กล่าวถึงโดย Antti ไม่สามารถใช้ได้
kvn

4
บรรทัดต่อไปนี้จะแบ่งส่วนทั่วไป: เชื่อมต่อ (สตริงใหม่ [] {"1"}, วัตถุใหม่ [] {วัตถุใหม่ ()})
dragon66

จะดีไม่ต้องใช้คำอธิบายประกอบ @SuppressWarnings - ฉันจะโพสต์วิธีแก้ปัญหาสำหรับด้านล่าง
beaudet

+1 Array.newInstance(a.getClass().getComponentType(), aLen + bLen);สำหรับ ฉันไม่เคยเห็นเรื่องนี้มาก่อนเลย @beaudet ฉันคิดว่าคำอธิบายประกอบใช้ได้ที่นี่พิจารณาว่าทำไมมันถึงถูกระงับ
เบลค

1
ฮาโทรหาฉันคนพิถีพิถัน แต่ฉันชอบรหัสสะอาดที่ไม่จำเป็นต้องมีการปราบปรามของคำเตือนเพื่อที่จะลบคำเตือน
27419

475

เป็นไปได้ที่จะเขียนเวอร์ชันทั่วไปอย่างสมบูรณ์ที่สามารถขยายเพื่อต่อเชื่อมอาร์เรย์จำนวนเท่าใดก็ได้ รุ่นนี้ต้องการ Java 6 ตามที่ใช้Arrays.copyOf()

ทั้งสองเวอร์ชันหลีกเลี่ยงการสร้างListวัตถุตัวกลางและใช้System.arraycopy()เพื่อให้แน่ใจว่าการคัดลอกอาร์เรย์ขนาดใหญ่เร็วที่สุด

สำหรับสองอาร์เรย์ดูเหมือนว่า:

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

และสำหรับจำนวนอาเรย์โดยพลการ (> = 1) ดูเหมือนว่า:

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: สำหรับอาร์เรย์ที่พิมพ์แบบดั้งเดิมคุณจะต้องโอเวอร์โหลดสำหรับแต่ละประเภท: เพียงคัดลอกโค้ดและแทนที่Tด้วยbyte(และสูญเสีย<T>)
Joachim Sauer

คุณกรุณาบอกวิธีใช้ตัวดำเนินการประเภท <T> ในชั้นเรียนของฉันได้ไหม
Johnydep

6
ฉันจะเพิ่มสิ่งนี้ไปยังจุดเริ่มต้นเพียงเพื่อจะป้องกัน if (first == null) {ถ้า (second == null) {return null; } คืนค่าวินาที; } if (second == null) {return ก่อน }
มาราธอน

4
@djBo: สิ่งที่เกี่ยวกับ:ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
แซมโกลด์เบิร์ก

18
มีข้อผิดพลาดในแนวทางนี้ซึ่งจะกลายเป็นที่เห็นได้ชัดถ้าคุณเรียกใช้ฟังก์ชั่นเหล่านี้กับอาร์เรย์ประเภทองค์ประกอบที่แตกต่างกันเช่นเป็นconcat(ai, ad)ที่aiเป็นInteger[]และเป็นad Double[](ในกรณีนี้พารามิเตอร์ type <T>จะได้รับการแก้ไข<? extends Number>โดยคอมไพเลอร์) อาร์เรย์ที่สร้างโดยArrays.copyOfจะมีประเภทองค์ประกอบของอาร์เรย์แรกเช่นIntegerในตัวอย่างนี้ เมื่อฟังก์ชันกำลังจะคัดลอกอาร์เรย์ที่สองArrayStoreExceptionจะถูกส่งออกไป วิธีแก้ไขคือมีClass<T> typeพารามิเตอร์เพิ่มเติม
T-Bull

457

ใช้Streamใน Java 8:

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

หรือเช่นนี้โดยใช้flatMap:

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

ในการทำเช่นนี้สำหรับประเภททั่วไปคุณต้องใช้การสะท้อนภาพ:

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

28
มันมีประสิทธิภาพแค่ไหน?
Supuhstar

8
เวิอ่าน: jaxenter.com/... - (? ไม่ได้นี้มีคำตอบเสมอฮ่า ๆ ) TL ดรลำธารอาจจะ performant หรือไม่ก็ขึ้นอยู่กับสิ่งที่คุณทำกับพวกเขาและข้อ จำกัด ของปัญหา
เทรเวอร์บราวน์

6
นอกจากนี้หากaหรือbเป็นอาร์เรย์ของประเภทดั้งเดิมการสตรีมของพวกเขาจะต้องเป็นแบบ.boxed()นั้นStreamแทนที่จะเป็นเช่นIntStreamซึ่งไม่สามารถส่งผ่านเป็นพารามิเตอร์ไปStream.concatได้
Will Hardwick-Smith

17
@Will ฮาร์ดวิคสมิ ธ : ไม่มีคุณจะต้องเลือกระดับกระแสที่เหมาะสมเช่นถ้าaและbมีint[]การใช้งานint[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
โฮล

3
@Supuhstar: System.arrayCopyมันอาจจะไม่เป็นอย่างรวดเร็ว แต่ก็ไม่ช้าเหมือนกัน คุณอาจจะต้องทำเรื่องนี้มากหลายครั้งที่มีขนาดใหญ่อาร์เรย์ในจริงๆบริบทประสิทธิภาพการทำงานที่มีความสำคัญสำหรับความแตกต่างของเวลาการดำเนินการในเรื่อง
Lii

191

หรือกับฝรั่งที่รัก:

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

นอกจากนี้ยังมีรุ่นสำหรับอาร์เรย์ดั้งเดิม:

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

เท่าที่ฉันรัก Guava วิธีการจาก Apache Commons เกี่ยวข้องกับ nullables ได้ดีขึ้น
Ravi Wallau

7
แม้ว่าจะเป็นการดีที่จะใช้ห้องสมุด แต่ก็โชคไม่ดีที่ปัญหาเกิดขึ้นแล้ว ดังนั้นโซลูชั่นพื้นฐานยังคงเข้าใจยาก
user924272

51
มีปัญหาอะไรกับสิ่งที่เป็นนามธรรม? Dunno จัดการกับการหมุนวนของล้อได้ที่นี่หากคุณต้องการเรียนรู้ปัญหาให้ตรวจสอบที่มาหรืออ่านมัน รหัสระดับมืออาชีพควรใช้ห้องสมุดระดับสูงดีกว่ามากหากพัฒนาขึ้นใน Google!
Breno Salgado

@RaviWallau คุณสามารถลิงค์ไปยังชั้นเรียนที่ทำสิ่งนี้ได้หรือไม่?
Sébastien Tromp

1
@ SébastienTrompมันเป็นคำตอบที่ดีที่สุดสำหรับคำถามนี้ - ArrayUtils
Ravi Wallau

70

คุณสามารถผนวกสองอาร์เรย์ในโค้ดสองบรรทัด

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

นี่เป็นวิธีแก้ปัญหาที่รวดเร็วและมีประสิทธิภาพและจะทำงานสำหรับประเภทดั้งเดิมรวมถึงวิธีการสองวิธีที่เกี่ยวข้องกับการโอเวอร์โหลด

คุณควรหลีกเลี่ยงการแก้ปัญหาที่เกี่ยวข้องกับ ArrayLists, สตรีม, ฯลฯ เนื่องจากสิ่งเหล่านี้จะต้องจัดสรรหน่วยความจำชั่วคราวสำหรับจุดประสงค์ที่ไม่มีประโยชน์

คุณควรหลีกเลี่ยงการforวนซ้ำสำหรับอาร์เรย์ขนาดใหญ่เนื่องจากสิ่งเหล่านี้ไม่มีประสิทธิภาพ วิธีการในตัวใช้ฟังก์ชั่นการคัดลอกบล็อกที่รวดเร็วมาก


1
นี่คือหนึ่งในโซลูชั่นที่ดีที่สุด Java มาตรฐาน 100% จาน / มีประสิทธิภาพ ควรได้รับ upvotes มากขึ้น!
Shebla Tsama

58

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

13
เพียง แต่ไม่มีประสิทธิภาพเนื่องจากมันสร้างอาร์เรย์สำหรับ ArrayList แล้วสร้างอีกวิธีสำหรับ toArray แต่ก็ยังใช้ได้เพราะอ่านง่าย
PhoneixS

1
บังคับสตริงและวัตถุ (เป็นคำถามที่ต้องการ) แต่ไม่มีวิธี addAll สำหรับประเภทหลัก (ตาม ints)
Joro

เนื้อหาที่อธิบายไว้ในบทความนี้การใช้both.toArray(new String[0])จะเร็วกว่าboth.toArray(new String[both.size()])แม้ว่ามันจะขัดแย้งกับสัญชาตญาณที่ไร้เดียงสาของเรา จึงเป็นสิ่งสำคัญที่ต้องวัดประสิทธิภาพที่แท้จริงเมื่อทำการปรับให้เหมาะสม หรือเพียงแค่ใช้โครงสร้างที่ง่ายกว่าเมื่อไม่สามารถพิสูจน์ความได้เปรียบของตัวแปรที่ซับซ้อนมากขึ้นได้
Holger

42

วิธีแก้ปัญหาjava เก่าและไม่มี 100%System.arraycopy (เช่นไม่มีในไคลเอนต์ 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;
}

ทำใหม่ของฉันสำหรับ File [] แต่มันเหมือนกัน ขอบคุณสำหรับวิธีแก้ปัญหาของคุณ
ShadowFlame

5
อาจจะค่อนข้างไม่มีประสิทธิภาพแม้ว่า
JonasCz - Reinstate Monica

คุณอาจต้องการเพิ่มการnullตรวจสอบ finalและบางทีอาจจะตั้งบางส่วนของตัวแปรของคุณจะ
Tripp Kinetics

@TrippKinetics nullเช็คจะซ่อน NPE มากกว่าที่จะแสดงพวกเขาและการใช้ขั้นสุดท้ายสำหรับ vars ในพื้นที่ยังไม่มีประโยชน์ใด ๆ (ยัง)
Maarten Bodewes

1
@Maarten Bodewes ฉันคิดว่าคุณจะพบ (ถ้าคุณเปรียบเทียบมันซึ่งฉันมี) ที่สำหรับแต่ละการทำงานในเวลาเดียวกับการวนรอบดัชนีใน Java รุ่นปลาย เครื่องมือเพิ่มประสิทธิภาพจะดูแลมัน
rghome

33

ฉันเพิ่งต่อสู้กับปัญหาการหมุนหน่วยความจำมากเกินไป หาก a และ / หรือ b เป็นที่รู้กันทั่วไปว่าว่างเปล่านี่คือการดัดแปลงรหัสของ silvertab (สร้างขึ้นด้วย):

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

แก้ไข: เวอร์ชันก่อนหน้าของโพสต์นี้ระบุว่าการใช้อาร์เรย์ซ้ำเช่นนี้จะต้องมีการบันทึกไว้อย่างชัดเจน เมื่อมาร์เท่นชี้ให้เห็นในความคิดเห็นโดยทั่วไปแล้วจะเป็นการดีกว่าที่จะลบคำสั่ง if ออกดังนั้นจึงจำเป็นต้องมีเอกสารประกอบ แต่จากนั้นอีกครั้งข้อความเหล่านั้นถ้าเป็นจุดรวมของการเพิ่มประสิทธิภาพเฉพาะนี้ตั้งแต่แรก ฉันจะทิ้งคำตอบไว้ที่นี่ แต่ระวัง!


5
อย่างไรก็ตามนี่หมายความว่าคุณกำลังส่งคืนอาเรย์เดียวกันและการเปลี่ยนค่าในอาเรย์ที่ส่งคืนจะเปลี่ยนค่าในตำแหน่งเดียวกันของอาเรย์อินพุตที่ส่งคืน
Lorenzo Boccaccia

ใช่ - ดูความคิดเห็นที่ส่วนท้ายของโพสต์ของฉันเกี่ยวกับการใช้อาร์เรย์ซ้ำ ค่าใช้จ่ายในการบำรุงรักษาที่กำหนดโดยโซลูชันนี้มีความคุ้มค่าในกรณีของเราโดยเฉพาะ แต่การทำสำเนาแบบป้องกันควรใช้ในกรณีส่วนใหญ่
วอลเลย์

Lorenzo / volley คุณสามารถอธิบายได้ว่าส่วนใดในรหัสที่ทำให้เกิดการใช้อาร์เรย์ซ้ำ ฉันคิดว่าSystem.arraycopyคัดลอกเนื้อหาของอาร์เรย์หรือไม่
Rosdi Kasim

4
โดยปกติผู้เรียกจะคาดหวังว่าการเรียกไปยัง concat () เพื่อส่งกลับอาร์เรย์ที่จัดสรรใหม่ หาก a หรือ b เป็นโมฆะ concat () จะส่งคืนหนึ่งในอาร์เรย์ที่ส่งเข้ามา การใช้ซ้ำนี้เป็นสิ่งที่คาดไม่ถึง (ใช่แล้วอาเรย์คัดลอกจะคัดลอกเท่านั้นการใช้ซ้ำมาจากการส่งคืน a หรือ b โดยตรง)
วอลเลย์

รหัสควรจะอธิบายด้วยตนเองมากที่สุด ผู้ที่อ่านโค้ดไม่จำเป็นต้องค้นหา JavaDoc ของฟังก์ชันที่เรียกว่าเพื่อค้นหาว่ามันทำสิ่งหนึ่งสำหรับเงื่อนไขเฉพาะและอีกสิ่งหนึ่งสำหรับอีกสิ่งหนึ่ง กล่าวโดยย่อ: โดยทั่วไปคุณไม่สามารถแก้ไขปัญหาการออกแบบเช่นนี้ได้พร้อมกับความคิดเห็น เพียงแค่ปล่อยสองifงบออกมาจะเป็นการแก้ไขที่ง่ายที่สุด
Maarten Bodewes

27

Java ทำงานห้องสมุดมีระดับอาร์เรย์เสื้อคลุมที่สวมใส่อาร์เรย์ด้วยวิธีการที่มีประโยชน์เช่นการเรียงต่อกัน

import static fj.data.Array.array;

... แล้ว

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

หากต้องการดึงอาเรย์ที่ยังไม่ได้เปิดออกให้โทรออก

String[] s = both.array();

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

both.toArray(new String[0]);

3
คำตอบนั้นยอดเยี่ยม แต่ก็หักนิดหน่อย เพื่อให้สมบูรณ์แบบคุณควรผ่านไปยังอาเรย์ () อาเรย์ประเภทที่คุณต้องการ ในตัวอย่างข้างต้นรหัสควรเป็น: both.toArray (สตริงใหม่ [0]) ดู: stackoverflow.com/questions/4042434/ …
Ronen Rabinovici

ไม่ทราบว่าทำไมคำตอบนี้ไม่ได้รับการจัดอันดับที่สูงขึ้น ... ถึงแม้ว่าจะต้องมีการเปลี่ยนแปลงที่เสนอโดย @RonenRabinovici
drmrbrewer

4
หรือดีกว่าโดยไม่ต้องจัดสรรอาร์เรย์ที่มีความยาวเป็นศูนย์โดยไม่จำเป็น: both.toArray(new String[both.size()]);)
Honza


สวัสดี @Honza เป็นไปได้ที่จะทำเช่นเดียวกันเพื่อกลับอาร์เรย์จำนวนเต็มดั้งเดิมใน 3 บรรทัด?
jumping_monkey

18

อีกวิธีหนึ่งกับ Java8 โดยใช้ 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

นี่คือการปรับเปลี่ยนโซลูชันของ silvertab โดยใช้ชุดติดตั้งทั่วไป:

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

หมายเหตุ: ดูคำตอบของ Joachimสำหรับวิธีแก้ปัญหา Java 6 ไม่เพียงกำจัดคำเตือนเท่านั้น มันสั้นกว่ามีประสิทธิภาพกว่าและอ่านง่ายกว่า!


คุณสามารถระงับคำเตือนสำหรับวิธีนี้ แต่นอกเหนือจากนั้นไม่มีอะไรที่คุณสามารถทำได้ อาร์เรย์และยาชื่อสามัญไม่ได้ผสมกันจริงๆ
Dan Dyer

3
คำเตือนที่ไม่ถูกตรวจสอบสามารถถูกกำจัดได้หากคุณใช้ Arrays.copyOf () ดูคำตอบของฉันสำหรับการใช้งาน
Joachim Sauer

@SuppressWarnings ("ไม่ จำกัด ")
Mark Renouf

13

หากคุณใช้วิธีนี้คุณจึงไม่จำเป็นต้องนำเข้าคลาสบุคคลที่สามใด ๆ

หากคุณต้องการเชื่อมต่อ String

โค้ดตัวอย่างสำหรับการเรียงสองสตริงอาเรย์

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

หากคุณต้องการเชื่อมต่อ Int

โค้ดตัวอย่างสำหรับการต่อสอง Integer Array

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

นี่คือวิธีการหลัก

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

        }
    }  

เราสามารถใช้วิธีนี้ได้เช่นกัน


11

โปรดยกโทษให้ฉันสำหรับการเพิ่มรุ่นอื่นลงในรายการที่มีความยาวแล้ว ฉันดูทุกคำตอบและตัดสินใจว่าฉันต้องการรุ่นที่มีพารามิเตอร์เพียงตัวเดียวในลายเซ็น ฉันยังเพิ่มการตรวจสอบข้อโต้แย้งบางอย่างเพื่อรับประโยชน์จากความล้มเหลวในช่วงต้นด้วยข้อมูลที่สมเหตุสมผลในกรณีที่มีการป้อนข้อมูลที่ไม่คาดคิด

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

ฉันจะสรุปความยาวในวงเดียวกับที่คุณทำการตรวจสอบโมฆะของคุณ - แต่นี่เป็นบทสรุปที่ดีจริงๆของคำตอบอื่น ๆ ที่นี่ ฉันเชื่อว่ามันจัดการประเภท intrinsic เช่น "int" โดยไม่ต้องเปลี่ยนเป็นวัตถุจำนวนเต็มซึ่งเป็นเหตุผลเดียวที่จัดการกับพวกเขาเป็นอาร์เรย์ไม่ใช่แค่เปลี่ยนทุกอย่างเป็น ArrayLists วิธีการของคุณอาจใช้ 2 อาร์เรย์และพารามิเตอร์ (... ) ดังนั้นผู้เรียกจึงรู้ว่าเขาต้องผ่านอย่างน้อยสองอาร์เรย์ก่อนที่เขาจะเรียกใช้และเห็นข้อผิดพลาด แต่นั่นทำให้รหัสลูปวนซับซ้อน ...
Bill K

11

คุณสามารถลองแปลงมันเป็น Arraylist และใช้เมธอด addAll จากนั้นแปลงกลับเป็นอาร์เรย์

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

วิธีแก้ปัญหาที่ดี - จะดีกว่าถ้ารหัสถูก refactored เพื่อหลีกเลี่ยงอาร์เรย์โดยรวมในความโปรดปรานของ ArrayLists แต่นั่นอยู่นอกการควบคุมของ "คำตอบ" และขึ้นอยู่กับผู้ถาม
Bill K

ฉันนับว่ามันต้องการวัตถุชั่วคราวอีก 4 ตัวที่จะทำงานได้
rghome

@rghome อย่างน้อยก็ไม่ต้องใช้ไลบรารีเพิ่มเติมเพื่อใช้งานง่าย ๆ เช่น
Farid

9

การใช้ Java 8+ สตรีมคุณสามารถเขียนฟังก์ชันต่อไปนี้:

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

7

นี่คือการใช้งานที่เป็นไปได้ในรหัสการทำงานของโซลูชันรหัสเทียมที่เขียนโดย silvertab

ขอบคุณ 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;
   }
}

ถัดไปคืออินเทอร์เฟซผู้สร้าง

หมายเหตุ: ตัวสร้างจำเป็นเพราะในจาวาไม่สามารถทำได้

new T[size]

เนื่องจากการลบประเภททั่วไป:

public interface ArrayBuilderI<T> {

   public T[] build(int size);
}

ต่อไปนี้เป็นเครื่องมือสร้างคอนกรีตที่ใช้อินเทอร์เฟซเพื่อสร้างIntegerอาร์เรย์

public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {

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

และในที่สุดแอปพลิเคชัน / ทดสอบ:

@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

นี่ควรเป็นหนึ่งซับ

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

6

ว้าว! มีคำตอบที่ซับซ้อนมากมายที่นี่รวมถึงคำตอบง่ายๆที่ขึ้นอยู่กับการอ้างอิงภายนอก วิธีทำแบบนี้:

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
.. แต่ไม่มีประสิทธิภาพและช้า
JonasCz - Reinstate Monica

6

ใช้งานได้ แต่คุณต้องแทรกการตรวจสอบข้อผิดพลาดของคุณเอง

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

มันอาจจะไม่ได้มีประสิทธิภาพมากที่สุด แต่ก็ไม่ได้พึ่งพา API ของ Java เอง


2
+1 มันจะเป็นการดีกว่าถ้าคุณจะแทนที่forลูปที่สองด้วย:for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
bancer

ใช้String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)เพื่อข้ามforลูปแรก arr1ช่วยประหยัดเวลาได้สัดส่วนกับขนาดของ
John Meyer

5

นี่คือฟังก์ชั่นที่แปลงแล้วสำหรับอาร์เรย์ 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

วิธีการเกี่ยวกับเพียงแค่

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

Array.concat(arr1, arr2)และเพียงแค่ทำ ตราบใดที่arr1และarr2เป็นประเภทเดียวกันสิ่งนี้จะทำให้คุณได้อาร์เรย์ประเภทเดียวกันที่มีทั้งสองอาร์เรย์


สำหรับเหตุผลด้านประสิทธิภาพฉันจะคำนวณขนาดสุดท้ายของ ArrayList ล่วงหน้าเพราะ ArrayList ตามคำนิยามจัดสรรอาร์เรย์ใหม่และคัดลอกองค์ประกอบของอาร์เรย์ทุกครั้งที่อาร์เรย์ปัจจุบันเต็ม มิฉะนั้นฉันจะตรงไปที่ LinkedList ซึ่งไม่ประสบปัญหาดังกล่าว
usr-local-ΕΨΗΕΛΩΝ

5

เวอร์ชันสแตติกทั่วไปที่ใช้ System.arraycopy ที่มีประสิทธิภาพสูงโดยไม่ต้องการคำอธิบายประกอบ @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

นี่คือ concatAll ของ Joachim Sauer ที่ได้รับการปรับปรุงเล็กน้อยของฉัน สามารถทำงานกับ Java 5 หรือ 6 ได้โดยใช้ System.arraycopy ของ Java 6 หากมีให้ใช้งานขณะใช้งานจริง วิธีนี้ (IMHO) เหมาะสำหรับ Android เพราะมันทำงานบน Android <9 (ซึ่งไม่มี System.arraycopy) แต่จะใช้วิธีที่เร็วกว่าถ้าเป็นไปได้

  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
แนวคิดทั่วไปที่ดี แต่สำหรับทุกคนที่ใช้งาน: ฉันต้องการรุ่น copyOf และ non-copyOf มากกว่าที่ทำทั้งสองอย่าง
rektide

4

อีกวิธีในการคิดถึงคำถาม ในการเชื่อมต่อสองแถวหรือมากกว่าเข้าด้วยกันสิ่งที่ต้องทำคือรายการองค์ประกอบทั้งหมดของแต่ละอาร์เรย์จากนั้นสร้างอาร์เรย์ใหม่ ดูเหมือนว่าจะสร้างList<T>และเรียกtoArrayใช้ บางคำตอบอื่นใช้ArrayListและนั่นก็ใช้ได้ แต่วิธีการเกี่ยวกับการใช้งานของเราเอง? มันไม่ยาก:

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

System.arraycopyผมเชื่อดังกล่าวข้างต้นจะเทียบเท่ากับการแก้ปัญหาที่ใช้ อย่างไรก็ตามฉันคิดว่าอันนี้มีความงามของตัวเอง


4

เกี่ยวกับ :

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

ชุดรูปแบบที่เรียบง่ายช่วยให้สามารถรวมอาร์เรย์ได้มากกว่าหนึ่งชุด:

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

ใช้ API ของ 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]);
}

ตอนนี้รหัสนี้ไม่ได้มีประสิทธิภาพมากที่สุด แต่มันอาศัยเฉพาะคลาส Java มาตรฐานและเข้าใจง่าย มันใช้งานได้กับจำนวนของ String [] (แม้จะมีอาร์เรย์เป็นศูนย์)


15
ต้อง downvote อันนี้สำหรับการสร้างรายการวัตถุที่ไม่จำเป็นทั้งหมด
Outlaw Programmer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.