แปลงอาร์เรย์ของ longs ดั้งเดิมเป็น List of Longs


138

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

long[] input = someAPI.getSomeLongs();
List<Long> inputAsList = Arrays.asList(input); //Total failure to even compile!

วิธีที่ถูกต้องในการทำเช่นนี้คืออะไร?


6
ฉันคิดว่าเรามีคำถามเดียวกันสำหรับ ints ใช่มั้ย
Tom Hawtin - tackline

คำตอบ:


115

ฉันพบว่าสะดวกในการใช้ apache commons lang ArrayUtils ( JavaDoc , การพึ่งพา Maven )

import org.apache.commons.lang3.ArrayUtils;
...
long[] input = someAPI.getSomeLongs();
Long[] inputBoxed = ArrayUtils.toObject(input);
List<Long> inputAsList = Arrays.asList(inputBoxed);

มันยังมี reverse API

long[] backToPrimitive = ArrayUtils.toPrimitive(objectArray);

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


3
เมื่อพิจารณาว่าสิ่งนี้สร้างอาร์เรย์ของ Longs ไม่ใช่ Listมันไม่ตอบคำถามของ OP และทำให้ downvote ของฉัน วิธีการที่ห่านี้ได้รับ 56 upvotes และ "ตรวจสอบ" เป็นเจ้าข้าวเจ้าของ?
user949300

7
เพราะคนที่สามารถทำArrays.asList(ArrayUtils.toObject(input))อาจจะ
Eran Medan

ฉันเห็นด้วยกับ @ user949300 สิ่งนี้ไม่ตอบคำถาม
dev4life

1
คำตอบนี้ควรได้รับการอัพเดตเพื่อให้การแปลงเสร็จสมบูรณ์ในรายการ อย่างไรก็ตามมันเป็นขั้นตอนที่มีประสิทธิภาพสำหรับการแก้ปัญหา
Jim Jeffers

2
@JimJeffers - ขอบคุณอัปเดตเพื่อรวมการแปลงที่สมบูรณ์แล้ว ตั้งแต่ OP รวมList<Long> = Arrays.asList(inputBoxed)ในคำถามของพวกเขาผมพบว่ามันซ้ำซ้อนที่จะทำซ้ำว่ามันเป็นฉันคิดว่ามันเป็นสิ่งที่ชัดเจนผมคิดว่าผมเป็นคนผิด ...
Eran เมดาน

114

ตั้งแต่ Java 8 ตอนนี้คุณสามารถใช้สตรีมสำหรับ:

long[] arr = {1,2,3,4};
List<Long> list = Arrays.stream(arr).boxed().collect(Collectors.toList());

7
ทำได้ดีนี่! แต่น่าเสียดายที่และค่อนข้างลึกลับที่streamฟังก์ชั่นที่มีการกำหนดเฉพาะสำหรับint[], และlong[] double[]
Norswap

1
LongStream.of(arr).boxed()...หรือคุณสามารถใช้
aioobe

2
Arrays.stream(arr).boxed().collect(Collectors.toList());น่าเสียดายที่สิ่งนี้สามารถกลับมาได้List<Object>
Senthilkumar Annadurai

ไม่มีไลบรารีขนาดใหญ่สำหรับงานง่ายไม่มีลูป คำตอบที่ดี
Alex Quilliam

37
import java.util.Arrays;
import org.apache.commons.lang.ArrayUtils;

List<Long> longs = Arrays.asList(ArrayUtils.toObject(new long[] {1,2,3,4}));

5
คำอธิบายว่าสิ่งนี้ทำอะไรและเป็นประโยชน์กับห้องสมุดของบุคคลที่สามหรือไม่
IgorGanapolsky

35

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

List<Long> list = new ArrayList<Long>(input.length);
for (long n : input)
  list.add(n);

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


1
ฉันมักจะทิ้งข้อกำหนดความยาวไว้นอกเสียจากว่ารหัสนั้นได้รับการพิสูจน์แล้วว่าเป็นส่วนหนึ่งของฮอตสปอตประสิทธิภาพหรืออาเรย์คาดว่าจะมีขนาดใหญ่มาก ฉันคิดว่าการละความยาวทำให้โค้ดอ่านง่ายขึ้นเล็กน้อย
hallidave

19

verbose อีกเล็กน้อย แต่ใช้งานได้:

    List<Long> list = new ArrayList<Long>();
    for (long value : input) {
        list.add(value);
    }

ในตัวอย่างของคุณปรากฏว่า Arrays.asList () กำลังตีความอินพุตเป็นรายการของอาร์เรย์ [] ยาวแทนที่จะเป็นรายการของ Longs ค่อนข้างน่าแปลกใจอย่างแน่นอน การล็อกอัตโนมัติไม่ทำงานตามที่คุณต้องการในกรณีนี้


17

ความเป็นไปได้อื่นไลบรารี Guavaให้สิ่งนี้เช่นเดียวLongs.asList()กับคลาสยูทิลิตี้ที่คล้ายกันสำหรับประเภทดั้งเดิมอื่น ๆ

import com.google.common.primitives.Longs;

long[] input = someAPI.getSomeLongs();
List<Long> output = Longs.asList(input);

7

ไม่ไม่มีการแปลงโดยอัตโนมัติจากอาเรย์ประเภทดั้งเดิมไปเป็นอาเรย์ของประเภทอ้างอิงแบบกล่อง คุณทำได้เท่านั้น

long[] input = someAPI.getSomeLongs();
List<Long> lst = new ArrayList<Long>();

for(long l : input) lst.add(l);

7

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

มีความแตกต่างที่สำคัญอย่างน้อยสองประการ:

  • ไม่ว่าจะเป็นรายการที่เกิดขึ้นควรจะเป็นมุมมองในอาร์เรย์หรือไม่ว่ามันควรจะเป็นรายการใหม่
  • ควรจะแก้ไขรายการผลลัพธ์หรือไม่

ตัวเลือกจะถูกสรุปที่นี่อย่างรวดเร็วและโปรแกรมตัวอย่างแบบสมบูรณ์จะแสดงที่ด้านล่างของคำตอบนี้


การสร้างรายการใหม่กับการสร้างมุมมองบนอาเรย์

เมื่อผลลัพธ์ควรเป็นรายการใหม่อาจใช้วิธีการหนึ่งจากคำตอบอื่น ๆ :

List<Long> list = Arrays.stream(array).boxed().collect(Collectors.toList());

แต่ควรพิจารณาข้อเสียของการทำเช่นนี้: อาร์เรย์ที่มีlongค่า1000000 จะครอบครองหน่วยความจำประมาณ 8 เมกะไบต์ รายการใหม่จะยังครอบครองประมาณ 8 เมกะไบต์ และแน่นอนว่าต้องมีการสำรวจเต็มรูปแบบในขณะที่สร้างรายการนี้ ในหลายกรณีการสร้างรายการใหม่นั้นไม่จำเป็น แต่มันก็เพียงพอแล้วที่จะสร้างมุมมองบนอาเรย์:

// This occupies ca. 8 MB
long array[] = { /* 1 million elements */ }

// Properly implemented, this list will only occupy a few bytes,
// and the array does NOT have to be traversed, meaning that this
// operation has nearly ZERO memory- and processing overhead:
List<Long> list = asList(array);

(ดูตัวอย่างที่ด้านล่างสำหรับการนำtoListวิธีการไปใช้)

ความหมายของการมีมุมมองในอาร์เรย์คือการเปลี่ยนแปลงในอาร์เรย์จะมองเห็นได้ในรายการ:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

System.out.println(list.get(1)); // This will print 34

// Modify the array contents:
array[1] = 12345;

System.out.println(list.get(1)); // This will now print 12345!

โชคดีที่การสร้างสำเนา (นั่นคือรายการใหม่ที่ไม่ได้รับผลกระทบจากการแก้ไขในอาร์เรย์) จากมุมมองนั้นเป็นเรื่องเล็กน้อย:

List<Long> copy = new ArrayList<Long>(asList(array));

ตอนนี้นี่เป็นสำเนาที่แท้จริงซึ่งเทียบเท่ากับสิ่งที่เกิดขึ้นกับโซลูชันที่ใช้สตรีมที่แสดงไว้ด้านบน


การสร้างมุมมองที่แก้ไขได้หรือมุมมองที่ไม่สามารถแก้ไขได้

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

การอนุญาตให้แก้ไขรายการทำให้เกิดคำถาม:

long array[] = { 12, 34, 56, 78 };
List<Long> list = asList(array);

list.set(2, 34567);           // Should this be possible?
System.out.println(array[2]); // Should this print 34567?
list.set(3, null);            // What should happen here?
list.add(99999);              // Should this be possible?

มันเป็นไปได้ในการสร้างมุมมองรายการในอาร์เรย์ที่สามารถปรับเปลี่ยนได้ ซึ่งหมายความว่าการเปลี่ยนแปลงในรายการเช่นการตั้งค่าใหม่ที่ดัชนีหนึ่งจะปรากฏในอาร์เรย์

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


ต่อไปนี้เป็นMCVE ที่แสดงตัวเลือกการใช้งานที่แตกต่างกันและวิธีที่เป็นไปได้ของการใช้รายการผลลัพธ์:

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.RandomAccess;

public class PrimitiveArraysAsLists
{
    public static void main(String[] args)
    {
        long array[] = { 12, 34, 56, 78 };

        // Create VIEWS on the given array
        List<Long> list = asList(array);
        List<Long> unmodifiableList = asUnmodifiableList(array);

        // If a NEW list is desired (and not a VIEW on the array), this
        // can be created as well:
        List<Long> copy = new ArrayList<Long>(asList(array));

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value in the array. The changes will be visible
        // in the list and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 1 of the array...");
        array[1] = 34567;

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        

        // Modify a value of the list. The changes will be visible
        // in the array and the unmodifiable list, but not in
        // the copy.
        System.out.println("Changing value at index 2 of the list...");
        list.set(2, 56789L);

        System.out.println("array           : " + Arrays.toString(array));
        System.out.println("list            : " + list);
        System.out.println("unmodifiableList: " + unmodifiableList);
        System.out.println("copy            : " + copy);        


        // Certain operations are not supported:
        try
        {
            // Throws an UnsupportedOperationException: This list is 
            // unmodifiable, because the "set" method is not implemented
            unmodifiableList.set(2, 23456L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }

        try
        {
            // Throws an UnsupportedOperationException: The size of the
            // backing array cannot be changed
            list.add(90L);
        }
        catch (UnsupportedOperationException e) 
        {
            System.out.println("Expected: " + e);
        }


        try
        {
            // Throws a NullPointerException: The value 'null' cannot be  
            // converted to a primitive 'long' value for the underlying array
            list.set(2, null);
        }
        catch (NullPointerException e)
        {
            System.out.println("Expected: " + e);
        }

    }

    /**
     * Returns an unmodifiable view on the given array, as a list.
     * Changes in the given array will be visible in the returned
     * list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asUnmodifiableList(long array[])
    {
        Objects.requireNonNull(array);
        class ResultList extends AbstractList<Long> implements RandomAccess
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
        return new ResultList();
    }

    /**
     * Returns a view on the given array, as a list. Changes in the given 
     * array will be visible in the returned list, and vice versa. The
     * list does not allow for <i>structural modifications</i>, meaning
     * that it is not possible to change the size of the list.
     *  
     * @param array The array
     * @return The list view
     */
    private static List<Long> asList(long array[])
    {
        Objects.requireNonNull(array);
        class ResultList extends AbstractList<Long> implements RandomAccess
        {
            @Override
            public Long get(int index)
            {
                return array[index];
            }

            @Override
            public Long set(int index, Long element)
            {
                long old = array[index];
                array[index] = element;
                return old;
            }

            @Override
            public int size()
            {
                return array.length;
            }
        };
        return new ResultList();
    }

}

ผลลัพธ์ของตัวอย่างจะแสดงที่นี่:

array           : [12, 34, 56, 78]
list            : [12, 34, 56, 78]
unmodifiableList: [12, 34, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 1 of the array...
array           : [12, 34567, 56, 78]
list            : [12, 34567, 56, 78]
unmodifiableList: [12, 34567, 56, 78]
copy            : [12, 34, 56, 78]
Changing value at index 2 of the list...
array           : [12, 34567, 56789, 78]
list            : [12, 34567, 56789, 78]
unmodifiableList: [12, 34567, 56789, 78]
copy            : [12, 34, 56, 78]
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.UnsupportedOperationException
Expected: java.lang.NullPointerException


6

ฉันกำลังเขียนห้องสมุดขนาดเล็กสำหรับปัญหาเหล่านี้:

long[] input = someAPI.getSomeLongs();
List<Long> = $(input).toList();

ในกรณีที่คุณสนใจตรวจสอบได้ที่นี่


ห้องสมุดที่ดี! ตอนแรกฉันไม่แน่ใจว่ามันคือ Java ... ฉันชอบสไตล์ JQuery
Yanick Rochon

4

อีกวิธีหนึ่งกับ Java 8

final long[] a = new long[]{1L, 2L};
final List<Long> l = Arrays.stream(a).boxed().collect(Collectors.toList());

1
เมื่อส่งคืนรายการ (ไม่ได้กำหนดไว้) ฉันพบว่าฉันต้องทำ:Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Jon

1
นี่เป็นเหมือนคำตอบที่มีอยู่นี้
ปาง

3

การรวมคำตอบของพาเวลและทอมเข้าด้วยกันเราได้สิ่งนี้มา

   @SuppressWarnings("unchecked")
    public static <T> List<T> asList(final Object array) {
        if (!array.getClass().isArray())
            throw new IllegalArgumentException("Not an array");
        return new AbstractList<T>() {
            @Override
            public T get(int index) {
                return (T) Array.get(array, index);
            }

            @Override
            public int size() {
                return Array.getLength(array);
            }
        };
    }

2

ถ้าคุณต้องการซีแมนทิกส์ที่คล้ายกันArrays.asListคุณจะต้องเขียน (หรือใช้ของคนอื่น) ในการนำไปใช้งานของลูกค้าList(อาจจะผ่านAbstractListมันควรมีการนำไปปฏิบัติแบบเดียวกันเช่นArrays.asListเดียวกับค่ากล่องและ unbox เท่านั้น


2

คุณสามารถใช้transmorph :

Transmorph transmorph = new Transmorph(new DefaultConverters());
List<Long> = transmorph.convert(new long[] {1,2,3,4}, new TypeReference<List<Long>>() {});

นอกจากนี้ยังใช้งานได้ถ้าแหล่งที่มาเป็นอาร์เรย์ของ ints เช่น


2

ฉันรู้ว่าคำถามนี้เก่าพอ แต่ ... คุณยังสามารถเขียนวิธีการแปลงของคุณเอง:

@SuppressWarnings("unchecked")
public static <T> List<T> toList(Object... items) {

    List<T> list = new ArrayList<T>();

    if (items.length == 1 && items[0].getClass().isArray()) {
        int length = Array.getLength(items[0]);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(items[0], i);
            T item = (T)element;
            list.add(item);
        }
    } else {
        for (Object i : items) {
            T item = (T)i;
            list.add(item);
        }
    }

    return list;
}

หลังจากที่คุณรวมมันโดยใช้การนำเข้าแบบคงที่ประเพณีที่เป็นไปได้อาจเป็น:

    long[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    List<Long> list = toList(array);

หรือ

    List<Long> list = toList(1l, 2l, 3l, 4l, 5l, 6l, 7l, 8l, 9l);

2
เกี่ยวกับ: catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }คุณเป็นคนที่น่ากลัว
Brandon Yarbrough

เฮ้ชายขอบคุณสำหรับสิ่งนั้น! คำพูดที่แดกดันของคุณทำให้ฉันหาทางออกที่ดีกว่า - รับความยาวของอาร์เรย์ผ่าน Array.getLength ()
Pavel Netesa

1
Fantastic! ฉันดีใจที่ทัศนคติที่ไม่ดีของฉันนำไปสู่ความก้าวหน้าแทนที่จะเป็นแค่ความรู้สึกไม่ดีทั่วไปทั่ว :) จริง ๆ แล้วมันไม่ใช่ความคิดที่ดีที่จะใช้ข้อยกเว้นยกเว้นในสภาวะที่ผิดปกติมาก พวกมันมีราคาแพงในการสร้าง เวอร์ชั่นใหม่นี้เร็วกว่ามาก
Brandon Yarbrough

1

ในขณะที่เป็นไปได้ในการสร้างรายการใหม่และเพิ่มค่าทั้งหมดลงในมัน (ผ่านสำหรับลูปหรือสตรีม) ฉันได้ทำงานกับอาร์เรย์ขนาดใหญ่จริงๆและรับประสิทธิภาพที่แย่ ดังนั้นฉันจึงสร้างคลาส wrapper อาร์เรย์ดั้งเดิมของฉันเองที่ใช้ง่าย

ตัวอย่าง:

long[] arr = new long[] {1,2,3};
PrimativeList<Long> list = PrimativeList.create(arr); // detects long[] and returns PrimativeList<Long>

System.out.println(list.get(1)); // prints: 2
list.set(2, 15);
System.out.println(arr[2]);  // prints: 15

รับได้ที่นี่: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java

หมายเหตุ: ฉันยังไม่ได้ทำการทดสอบอย่างสมบูรณ์ดังนั้นโปรดแจ้งให้เราทราบหากคุณพบข้อบกพร่อง / ปัญหาใด ๆ


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