Konvertieren Sie ein Array primitiver Longs in eine Liste von Longs


138

Dies mag eine einfache Frage sein, aber mein erster Versuch schlug überraschenderweise völlig fehl. Ich wollte eine Reihe primitiver Longs nehmen und daraus eine Liste machen, was ich so versuchte:

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

Was ist der richtige Weg, um dies zu tun?


6
Ich denke, wir hatten die gleiche Frage für Ints, nicht wahr?
Tom Hawtin - Tackline

Antworten:


115

Ich fand es praktisch, Apache Commons Lang ArrayUtils ( JavaDoc , Maven-Abhängigkeit ) zu verwenden.

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

Es hat auch die umgekehrte API

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

BEARBEITEN: aktualisiert, um eine vollständige Konvertierung in eine Liste bereitzustellen, wie in Kommentaren und anderen Korrekturen vorgeschlagen.


3
In Anbetracht dessen, dass dies ein Array von Longs erstellt, keine Liste , beantwortet es nicht die Frage von OP und erhält meine Ablehnung. Wie zum Teufel hat das 56 Upvotes und den begehrten "Scheck" bekommen ???
user949300

7
Weil die Leute das Arrays.asList(ArrayUtils.toObject(input))wahrscheinlich leicht können .
Eran Medan

Ich stimme @ user949300 zu. Dies beantwortet die Frage nicht.
dev4life

1
Diese Antwort sollte aktualisiert werden, um eine vollständige Konvertierung in eine Liste zu ermöglichen. Dies ist jedoch ein effizienter Schritt in Richtung der Lösung.
Jim Jeffers

2
@ JimJeffers - danke, aktualisiert, um die vollständige Konvertierung einzuschließen. Da das OP List<Long> = Arrays.asList(inputBoxed)in ihrer Frage enthalten war, fand ich es überflüssig, es zu wiederholen, da ich es für offensichtlich hielt, ich glaube, ich habe mich geirrt ...
Eran Medan

114

Seit Java 8 können Sie jetzt Streams dafür verwenden:

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

7
Schön! Leider und etwas geheimnisvoll, die streamist Funktion nur definiert int[], long[]und double[].
Norswap

1
Alternativ können Sie verwenden LongStream.of(arr).boxed()....
Aioobe

2
Arrays.stream(arr).boxed().collect(Collectors.toList());Leider kann dies nur zurückkehrenList<Object>
Senthilkumar Annadurai

Keine sperrigen Bibliotheken für eine einfache Aufgabe, keine Schleifen. Gute Antwort.
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
Eine Erklärung, was dies bewirkt und ob es sich um eine Bibliothek eines Drittanbieters handelt, wäre hilfreich.
Igor Ganapolsky

35

hallidave und jpalecek haben die richtige Idee - sie iterieren über ein Array -, nutzen jedoch nicht die Funktionen von ArrayList: Da die Größe der Liste in diesem Fall bekannt ist, sollten Sie sie beim Erstellen der Liste angeben ArrayList.

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

Auf diese Weise werden keine unnötigen Arrays erstellt, die nur von den verworfen werden, ArrayListweil sie sich als zu kurz herausstellen, und es werden keine leeren "Slots" verschwendet, weil ArrayListder Platzbedarf überschätzt wurde. Wenn Sie der Liste weiterhin Elemente hinzufügen, wird natürlich ein neues Hintergrundarray benötigt.


1
Ich neige dazu, die Längenangabe wegzulassen, es sei denn, der Code ist nachweislich Teil eines Leistungs-Hotspots oder es wird erwartet, dass das Array extrem groß ist. Ich denke, dass das Weglassen der Länge den Code etwas lesbarer macht.
Hallidave

19

Ein bisschen ausführlicher, aber das funktioniert:

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

In Ihrem Beispiel scheint Arrays.asList () die Eingabe als Liste von langen [] Arrays anstelle einer Liste von Longs zu interpretieren. Sicher ein bisschen überraschend. Autoboxing funktioniert in diesem Fall einfach nicht so, wie Sie es möchten.


17

Als eine andere Möglichkeit, die Guava Bibliothek bietet dies als Longs.asList(), mit ähnlichen Utility - Klassen für die anderen primitiven Typen.

import com.google.common.primitives.Longs;

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

7

Nein, es gibt keine automatische Konvertierung von einem Array vom primitiven Typ in ein Array ihrer Referenztypen. Das kannst du nur

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

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

7

Die Frage lautete, wie ein Array in eine Liste umgewandelt werden kann. Die meisten Antworten zeigten bisher, wie eine neue Liste mit demselben Inhalt wie das Array erstellt oder auf Bibliotheken von Drittanbietern verwiesen wird. Es gibt jedoch einfache, integrierte Optionen für diese Art der Konvertierung. Einige von ihnen wurden bereits in anderen Antworten skizziert (z . B. diese ). Ich möchte hier jedoch auf bestimmte Freiheitsgrade für die Implementierung hinweisen und diese ausarbeiten und die potenziellen Vor- und Nachteile sowie Vorbehalte aufzeigen.

Es sind mindestens zwei wichtige Unterscheidungen zu treffen:

  • Gibt an, ob die resultierende Liste eine Ansicht des Arrays oder eine neue Liste sein soll
  • Ob die resultierende Liste geändert werden soll oder nicht

Die Optionen werden hier schnell zusammengefasst, und am Ende dieser Antwort wird ein vollständiges Beispielprogramm angezeigt.


Erstellen einer neuen Liste im Vergleich zum Erstellen einer Ansicht des Arrays

Wenn das Ergebnis eine neue Liste sein soll, kann einer der Ansätze aus den anderen Antworten verwendet werden:

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

Dabei sollten jedoch die Nachteile berücksichtigt werden: Ein Array mit 1000000- longWerten belegt ungefähr 8 Megabyte Speicher. Die neue Liste wird auch ungefähr 8 Megabyte belegen. Und natürlich muss beim Erstellen dieser Liste das gesamte Array durchlaufen werden. In vielen Fällen ist das Erstellen einer neuen Liste einfach nicht erforderlich. Stattdessen reicht es aus, eine Ansicht des Arrays zu erstellen :

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

(Eine Implementierung der toListMethode finden Sie im Beispiel unten. )

Wenn Sie eine Ansicht des Arrays haben, bedeutet dies, dass Änderungen im Array in der Liste sichtbar sind:

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!

Glücklicherweise ist das Erstellen einer Kopie (dh einer neuen Liste, die nicht von Änderungen im Array betroffen ist) aus der Ansicht trivial:

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

Dies ist eine echte Kopie, die dem entspricht, was mit der oben gezeigten Stream-basierten Lösung erreicht wird.


Erstellen einer veränderbaren oder einer nicht veränderbaren Ansicht

In vielen Fällen ist es ausreichend, wenn die Liste schreibgeschützt ist . Der Inhalt der resultierenden Liste wird häufig nicht geändert, sondern nur an die nachgeschaltete Verarbeitung übergeben, die nur die Liste liest.

Das Zulassen von Änderungen an der Liste wirft einige Fragen auf:

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?

Es ist möglich, eine Listenansicht für das Array zu erstellen, die geändert werden kann . Dies bedeutet, dass Änderungen in der Liste, wie das Festlegen eines neuen Werts für einen bestimmten Index, im Array sichtbar sind.

Es ist jedoch nicht möglich, eine Listenansicht zu erstellen, die strukturell geändert werden kann . Dies bedeutet, dass keine Vorgänge ausgeführt werden können, die sich auf die Größe der Liste auswirken . Dies liegt einfach daran, dass die Größe des zugrunde liegenden Arrays nicht geändert werden kann.


Das folgende MCVE zeigt die verschiedenen Implementierungsoptionen und die möglichen Verwendungsmöglichkeiten der resultierenden Listen:

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

}

Die Ausgabe des Beispiels wird hier gezeigt:

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

Ein anderer Weg mit Java 8.

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

6

Ich schreibe eine kleine Bibliothek für diese Probleme:

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

Falls es Sie interessiert, überprüfen Sie es hier .


schöne Bibliothek! Zuerst war ich mir nicht sicher, ob es Java war ... Ich mag den JQuery-Stil
Yanick Rochon

4

Ein anderer Weg mit Java 8.

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

1
Als ich die Liste zurückgab (ohne sie Arrays.stream(a).boxed().collect(Collectors.<Long>toList());
Jon

1
Dies ist identisch mit dieser vorhandenen Antwort .
Pang

3

Wenn wir die Antworten von Pavel und Tom kombinieren, erhalten wir dies

   @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

Wenn Sie eine ähnliche Semantik wünschen, müssen Arrays.asListSie die Kundenimplementierung von List(wahrscheinlich bis) schreiben (oder verwenden) AbstractList. Sie sollte Arrays.asListungefähr dieselbe Implementierung haben wie nur Box- und Unbox-Werte.


2

Sie können transmorph verwenden :

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

Dies funktioniert auch, wenn die Quelle beispielsweise ein Array von Ints ist.


2

Ich weiß, dass diese Frage alt genug ist, aber ... Sie können auch Ihre eigene Konvertierungsmethode schreiben:

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

Nachdem Sie es mithilfe des statischen Imports eingefügt haben, können folgende Verwendungszwecke auftreten:

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

oder

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

2
in Bezug auf : catch (ArrayIndexOutOfBoundsException ex) { /* Finished getting array elements */ }, Sie sind eine schreckliche Person.
Brandon Yarbrough

Hey Mann, danke dafür! Ihre ironische Bemerkung hat mich dazu gebracht, eine bessere Lösung zu finden - die Länge des Arrays über Array.getLength () zu ermitteln.
Pavel Netesa

1
Fantastisch! Ich bin froh, dass meine sardonische Haltung zu Fortschritten geführt hat, anstatt nur allgemeine schlechte Gefühle zu haben :) Wirklich, es ist keine gute Idee, Ausnahmen zu verwenden, außer unter sehr ungewöhnlichen Bedingungen. Ihre Herstellung ist überraschend teuer. Diese neue Version ist viel, viel schneller.
Brandon Yarbrough

1

Während es möglich ist, eine neue Liste zu erstellen und alle Werte hinzuzufügen (via for-Schleife oder Streams), habe ich an wirklich großen Arrays gearbeitet und eine schlechte Leistung erzielt. Daher habe ich meine eigene benutzerfreundliche primitive Array-Wrapper-Klasse erstellt.

Beispiel:

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

Erhalten Sie es hier: https://github.com/Sf298/Sauds-Toolbox/blob/master/src/main/java/PrimitiveArrayWrapper/PrimitiveList.java

HINWEIS: Ich habe es noch nicht vollständig getestet. Lassen Sie mich wissen, wenn Sie Fehler / Probleme finden.


0

Sie können verwendet werden LongStreamfür die

List<Long> longs = LongStream.of(new long[]{1L, 2L, 3L}).boxed()
                             .collect(Collectors.toList());
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.