Bir dizi ilkel uzun ürün dizisini Uzun ürün listesine dönüştürme


138

Bu biraz kolay, headdesk bir soru olabilir, ama ilk denemem şaşırtıcı bir şekilde tamamen başarısız oldu. Ben ilkel uzun bir dizi almak ve bunu yapmaya çalıştım bir liste haline getirmek istedim:

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

Bunu yapmanın doğru yolu nedir?


6
Sanırım ints için aynı soruyu sorduk, değil mi?
Tom Hawtin - tackline

Yanıtlar:


115

Ben apray commons lang ArrayUtils ( JavaDoc , Maven bağımlılığı ) kullanarak yapmak uygun buldum

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

ayrıca ters API'ye sahiptir

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

EDIT: Yorumlar ve diğer düzeltmeler tarafından önerilen bir listeye tam bir dönüşüm sağlamak için güncellendi.


3
Bunun bir Liste değil, bir Longs dizisi oluşturduğu düşünüldüğünde, OP'nin sorusuna cevap vermez ve benim oyumu alır. Bu nasıl 56 upvotes ve açgözlü "kontrol" aldın?
user949300

7
Çünkü insanlar Arrays.asList(ArrayUtils.toObject(input))muhtemelen kolayca yapabilirler .
Eran Medan

@ User949300 ile katılıyorum. Bu soruya cevap vermiyor.
dev4life

1
Bu cevap, listeye tam bir dönüşüm sağlamak için güncellenmelidir. Ancak, çözüm yolunda etkili bir adımdır.
Jim Jeffers

2
@JJJeffers - teşekkürler, tam dönüşümü içerecek şekilde güncellendi. OP List<Long> = Arrays.asList(inputBoxed)sorularına dahil olduğundan , açık olduğunu düşündüğüm gibi tekrarlamayı gereksiz buldum, sanırım yanılmışım ...
Eran Medan

114

Java 8'den beri bunun için akışları kullanabilirsiniz:

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

7
Güzel bir! Ne yazık ki, ve biraz gizemli streamfonksiyon sadece için tanımlandığı int[], long[]ve double[].
Norswap

1
Alternatif olarak kullanabilirsiniz LongStream.of(arr).boxed()....
aioobe

2
Arrays.stream(arr).boxed().collect(Collectors.toList());Ne yazık ki bu sadece geri dönebilirList<Object>
Senthilkumar Annadurai

Basit bir görev için hantal kütüphaneler yok, döngüler yok. Mükemmel cevap.
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
Bunun ne yaptığına ve bunun bir üçüncü taraf kütüphanesi olup olmadığına dair bir açıklama yardımcı olacaktır.
IgorGanapolsky

35

hallidave ve jpalecek doğru bir fikre sahiptir - bir dizi üzerinden yineleme - ancak bu özellik tarafından sağlanan bir özellikten faydalanmazlar ArrayList: bu durumda listenin boyutu bilindiğinden , oluştururken bunu belirtmelisiniz ArrayList.

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

Bu şekilde, gereksiz diziler yalnızca atılmaları için yaratılmazlar ArrayListçünkü çok kısa oldukları ortaya çıkar ArrayListve boşluk gereksinimlerini fazla tahmin ettiği için boş "yuva" israf edilmez. Elbette, listeye eleman eklemeye devam ederseniz, yeni bir destek dizisine ihtiyaç duyulacaktır.


1
Kod bir performans sıcak nokta parçası olduğu kanıtlanmadığı veya dizi son derece büyük olması bekleniyor sürece uzunluk özelliklerini dışarıda bırakma eğilimindedir. Uzunluğunu bırakmak kodu biraz daha okunabilir hale getirdiğini düşünüyorum.
hallidave

19

Biraz daha ayrıntılı, ama bu işe yarıyor:

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

Örneğinizde, Arrays.asList () öğesinin, Longs listesi yerine long [] dizileri listesi olarak yorumladığı anlaşılıyor. Kesinlikle biraz şaşırtıcı. Otomatik kutulama bu durumda istediğiniz şekilde çalışmaz.


17

Başka bir olasılık olarak, Guava kütüphanesi bunu Longs.asList()diğer ilkel tipler için benzer yardımcı sınıflarla sağlar.

import com.google.common.primitives.Longs;

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

7

Hayır, ilkel tür dizisinden kutulu referans türlerinin dizisine otomatik dönüşüm yoktur. Sadece yapabilirsin

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

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

7

Soru, bir dizinin listeye nasıl dönüştürüleceğini sordu. Şimdiye kadar cevapların çoğu , diziyle aynı içeriğe sahip yeni bir listenin nasıl oluşturulacağını veya üçüncü taraf kitaplıklarına atıfta bulunulduğunu gösterdi. Ancak, bu tür bir dönüşüm için basit, yerleşik seçenekler vardır. Bazıları zaten (diğer yanıtlar örneğin kabataslak edilmiş bu bir ). Ancak, burada uygulama için belirli derecede serbestlik konularına dikkat çekmek ve potansiyel faydaları, dezavantajları ve uyarıları göstermek istiyorum.

Yapılacak en az iki önemli ayrım vardır:

  • Sonuçta elde edilen listenin dizi üzerinde bir görünüm olup olmadığı veya yeni bir liste olup olmadığı
  • Ortaya çıkan liste olmalıdır olsun değiştirilebilir veya olmasın

Seçenekler burada hızlı bir şekilde özetlenecek ve bu cevabın altında tam bir örnek program gösterilecektir.


Dizide görünüm oluşturmaya karşı yeni bir liste oluşturma

Sonuç yeni bir liste olduğunda, diğer cevaplardan yaklaşımlardan biri kullanılabilir:

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

Ancak bunu yapmanın dezavantajları düşünülmelidir: 1000000 longdeğerine sahip bir dizi kabaca 8 Megabayt bellek kaplayacaktır. Yeni liste ayrıca yaklaşık 8 Megabayt kaplayacak. Ve elbette, bu liste oluşturulurken tam dizi geçilmelidir. Çoğu durumda, yeni bir liste oluşturmak gerekli değildir. Bunun yerine, dizide bir görünüm oluşturmak yeterlidir :

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

( toListYöntemin uygulanması için alttaki örneğe bakın )

Dizide bir görünüme sahip olmanın anlamı , dizideki değişikliklerin listede görünür olmasıdır:

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!

Neyse ki, görünümden bir kopya (yani, dizideki değişikliklerden etkilenmeyen yeni bir liste) oluşturmak önemsizdir:

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

Şimdi, bu, yukarıda gösterilen akış tabanlı çözümle elde edilene eşdeğer gerçek bir kopyadır.


Bir oluşturma değiştirilebilir bir görünüm veya değiştirilemeyen bir görünüm

Çoğu durumda, liste salt okunur olduğunda yeterli olacaktır . Ortaya çıkan listenin içeriği genellikle değiştirilmez, yalnızca listeyi okuyan aşağı akış işlemine geçirilir.

Listede değişiklik yapılmasına izin verilmesi bazı sorulara neden olur:

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?

Dizide değiştirilebilir bir liste görünümü oluşturmak mümkündür . Bu, listedeki belirli bir dizinde yeni bir değer ayarlamak gibi değişikliklerin dizide görüneceği anlamına gelir.

Ancak yapısal olarak değiştirilebilen bir liste görünümü oluşturmak mümkün değildir . Bu , listenin boyutunu etkileyen işlemlerin yapılamayacağı anlamına gelir . Bunun nedeni temeldeki dizinin boyutunun değiştirilememesidir.


Aşağıda, farklı uygulama seçeneklerini ve sonuçta ortaya çıkan listeleri kullanmanın olası yollarını gösteren bir MCVE yer almaktadır:

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

}

Örneğin çıktısı burada gösterilmiştir:

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

Java 8 ile başka bir yol.

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

6

Bu sorunlar için küçük bir kütüphane yazıyorum:

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

Önem verdiğinizde buradan kontrol edin .


güzel kütüphane! ilk başta, Java olduğundan emin değildim ... JQuery stilini seviyorum
Yanick Rochon

4

Java 8 ile başka bir yol .

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

1
Listeyi döndürürken (atamadan), yapmam gerektiğine karar verdim:Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Jon

1
Bu mevcut cevapla aynıdır .
Pang

3

Pavel ve Tom'un cevaplarını birleştirerek bunu elde ederiz

   @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

Eğer benzer semantik istiyorsanız Arrays.asListo zaman yazma (veya kullanım başkasının) müşteri uygulanması gerekir List(muhtemelen içinden AbstractList. Çok daha aynı uygulamaya sahip olmalıdır Arrays.asList, sadece kutu ve Unbox değerleri.


2

Transmorf kullanabilirsiniz :

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

Kaynak örneğin bir ints dizisi ise de çalışır.


2

Bu sorunun yeterince eski olduğunu biliyorum, ama ... kendi dönüşüm yönteminizi de yazabilirsiniz:

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

Statik içe aktarmayı kullanarak ekledikten sonra, olası kullanımlar şunlar olabilir:

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

veya

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

2
ile ilgili olarak: catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }korkunç bir insansın.
Brandon Yarbrough

Hey dostum, bunun için teşekkürler! İronik sözün daha iyi bir çözüm bulmamı sağladı - dizinin uzunluğunu Array.getLength () ile elde ettim.
Pavel Netesa

1
Fantastik! Her yerde sadece genel kötü duygular yerine ilerlemeye yol açan sevindim sevindim :) Gerçekten, çok sıradışı koşullar dışında istisnalar kullanmak iyi bir fikir değil. Yaratmaları şaşırtıcı derecede pahalı. Bu yeni sürüm çok, çok daha hızlı.
Brandon Yarbrough

1

Yeni bir Liste oluşturmak ve tüm değerleri (döngü veya akışlar için) eklemek mümkün olsa da, gerçekten büyük diziler üzerinde çalışıyorum ve düşük performans elde ediyorum. Bu yüzden kendi kullanımı kolay ilkel dizi sarmalayıcı sınıfı oluşturdum.

Misal:

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

Buradan edinin: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java

NOT: Henüz tam olarak test etmedim, bu yüzden herhangi bir hata / sorun bulursanız bana bildirin.


0

Sen kullanabilirsiniz LongStreambunun için

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.