programing tip

기본 long 배열을 Long 목록으로 변환

itbloger 2020. 6. 29. 08:13
반응형

기본 long 배열을 Long 목록으로 변환


이것은 다소 쉬운 헤드 데스크 질문 일지 모르지만 첫 번째 시도는 놀랍게도 완전히 실패했습니다. 나는 원시적 인 long 배열을 가져 와서 목록으로 바꾸고 싶었습니다.

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

이것을하는 올바른 방법은 무엇입니까?


아파치 커먼즈 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);

또한 역 API가 있습니다

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

편집 : 의견 및 기타 수정 사항에서 제안한대로 목록으로 완전히 변환되도록 업데이트되었습니다.


Java 8부터는 다음과 같은 스트림을 사용할 수 있습니다.

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

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

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

hallidavejpalecek 은 배열에 대해 올바른 아이디어를 가지고 있지만 다음과 같은 기능을 활용하지 않습니다 ArrayList. 이 경우 목록의 크기가 알려져 있으므로를 만들 때 지정해야합니다 ArrayList.

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

이런 식으로 불필요한 배열은 ArrayList너무 짧아서 폐기하기 위해 만들어 지지 않으며 ArrayList공간 요구 사항을 과대 평가하여 빈 "슬롯"이 낭비되지 않습니다 . 물론 목록에 요소를 계속 추가하면 새로운 백업 배열이 필요합니다.


조금 더 장황하지만 작동합니다.

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

귀하의 예에서 Arrays.asList ()는 입력을 Long 목록 대신 long [] 배열 목록으로 해석하는 것으로 보입니다. 확실히 조금 놀랍습니다. 이 경우 오토 박싱은 원하는 방식으로 작동하지 않습니다.


또 다른 가능성으로, 구아바 라이브러리 는이를 Longs.asList()다른 기본 유형에 대한 유사한 유틸리티 클래스와 함께 로 제공합니다 .

import com.google.common.primitives.Longs;

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

아니요, 기본 유형의 배열에서 박스형 참조 유형의 배열로 자동 변환되지 않습니다. 당신은 할 수만 있습니다

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

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

Java 8의 또 다른 방법.

long[] input = someAPI.getSomeLongs();
LongStream.of(input).boxed().collect(Collectors.toList()));

이 문제에 대한 작은 라이브러리를 작성 중입니다.

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

당신이 걱정하는 경우 여기를 확인 하십시오 .


질문은 배열을 목록으로 바꾸는 방법에 대해 물었습니다. 지금까지 대부분의 답변 은 배열과 동일한 내용으로 새로운 목록 을 작성 하거나 타사 라이브러리를 참조 하는 방법을 보여주었습니다 . 그러나 이러한 종류의 변환에는 간단한 기본 제공 옵션이 있습니다. 그들 중 일부는 이미 다른 답변 (예 : this one ) 으로 스케치되었습니다 . 그러나 나는 여기서 구현에 대한 특정 자유도를 지적하고 구체화하고 잠재적 이점, 단점 및 경고를 보여주고 싶습니다.

최소한 두 가지 중요한 차이점이 있습니다.

  • 결과 목록이 배열 인지 아니면 목록 이어야하는지 여부
  • 결과 목록이되어야하는지 여부를 수정 여부

옵션은 여기에 빠르게 요약되며이 예제의 맨 아래에 완전한 예제 프로그램이 표시됩니다.


새 목록 만들기와 배열 에서 보기 만들기

결과가 새로운 목록 이어야하는 경우 다른 답변의 접근 방식 중 하나를 사용할 수 있습니다.

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

그러나이 작업의 단점을 고려해야합니다. long값이 1000000 인 배열 은 약 8MB의 메모리를 차지합니다. 새로운 목록 약 8MB를 차지할 입니다. 물론이 목록을 작성하는 동안 전체 배열을 순회해야합니다. 많은 경우 새 목록을 만들 필요가 없습니다. 대신 배열 에서 보기 를 작성하면 충분합니다 .

// 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

Pavel과 Tom의 답변을 결합하면 다음과 같이됩니다.

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

Java 8의 또 다른 방법 .

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

If you want similar semantics to Arrays.asList then you'll need to write (or use someone else's) customer implementation of List (probably through AbstractList. It should have much the same implementation as Arrays.asList, only box and unbox values.


You can use transmorph :

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

It also works if source is an array of ints for example.


I know this question is old enough, but... you can also write your own conversion method:

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

After you include it using static import, possible usages could be:

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

or

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

While it is possible to create a new List and add all the values to it (via for loop or streams), I have been working on really big arrays and get poor performance. Therefore I created my own easy to use primitive array wrapper class.

Example:

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

Get it here: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java

NOTE: I haven't fully tested it yet, so let me know if you find any bugs/issues.


You can use LongStream for that

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());

참고URL : https://stackoverflow.com/questions/754294/convert-an-array-of-primitive-longs-into-a-list-of-longs

반응형