Hoe List<Integer> te converteren naar int[] in Java?

Dit is vergelijkbaar met deze vraag:
Hoe converteer ik int[] naar Integer[] in Java?

Ik ben nieuw op Java. Hoe kan ik een List<Integer>converteren naar int[]in Java? Ik ben in de war omdat List.toArray()eigenlijk een Object[]retourneert, die kan worden gecast naar onder Integer[]of int[].

Op dit moment gebruik ik een lus om dit te doen:

int[] toIntArray(List<Integer> list){
  int[] ret = new int[list.size()];
  for(int i = 0;i < ret.length;i++)
    ret[i] = list.get(i);
  return ret;
}

Ik weet zeker dat er een betere manier is om dit te doen.


Antwoord 1, autoriteit 100%

Helaas geloof ik niet dat er echt iseen betere manier om dit te doen vanwege de aard van Java’s omgang met primitieve typen, boxing, arrays en generieke middelen. In het bijzonder:

  • List<T>.toArraywerkt niet omdat er geen conversie is van Integernaar int
  • Je kunt intniet gebruiken als typeargument voor generieke geneesmiddelen, dus het zou moeteneen int-specifieke methode zijn (of een die reflectie gebruikte om vervelende bedrog uit te voeren).

Ik geloof dat er bibliotheken zijn die automatisch gegenereerde versies van dit soort methode hebben voor alle primitieve typen (d.w.z. er is een sjabloon dat voor elk type wordt gekopieerd). Het is lelijk, maar zo is het ben ik bang 🙁

Hoewel de Arraysklasse uitkwam voordat generieke geneesmiddelen in Java arriveerden, zou het nog steeds alle vreselijke overbelastingen moeten bevatten als het vandaag zou worden geïntroduceerd (ervan uitgaande dat je primitieve arrays wilt gebruiken).


Antwoord 2, autoriteit 94%

Niemand heeft het nog over streams toegevoegd in Java 8, dus hier komt het:

int[] array = list.stream().mapToInt(i->i).toArray();
//OR
//int[] array = list.stream().mapToInt(Integer::intValue).toArray();

Denkproces:

  • eenvoudige Stream#toArrayretourneert Object[], dus het is niet wat we willen. Ook Stream#toArray(IntFunction<A[]> generator)doet niet wat we willen omdat generiek type Aprimitieve int

  • dus het zou leuk zijn om een ​​stream te hebben die het primitieve type intaankan in plaats van wrapper Integer, omdat het toArrayis methode zal hoogstwaarschijnlijk ook int[]array retourneren (het retourneren van iets anders zoals Object[]of zelfs boxed Integer[]zou hier onnatuurlijk zijn) . En gelukkig heeft Java 8 zo’n stream die IntStream

  • Dus nu hoeven we alleen nog uit te zoeken hoe we onze Stream<Integer>moeten converteren (die wordt geretourneerd door list.stream()) naar die glanzende IntStream. Hier Stream#mapToInt(ToIntFunction<? super T> mapper)-methode komt te hulp. Het enige wat we hoeven te doen is de mapping door te geven van Integernaar int.

    We zouden zoiets kunnen gebruiken als Integer#intValuewat intals resultaat geeft:

    mapToInt( (Integer i) -> i.intValue() )  
    

    (of als iemand de voorkeur geeft aan mapToInt(Integer::intValue))

    maar vergelijkbare code kan worden gegenereerd met behulp van unboxing, omdat de compiler weet dat het resultaat van deze lambda intmoet zijn (lambda in mapToIntis de implementatie van ToIntFunctioninterface die body verwacht voor int applyAsInt(T value)methode die naar verwachting intzal retourneren).

    Dus we kunnen gewoon schrijven

    mapToInt((Integer i)->i)
    

    Ook aangezien Integer(Integer i)typt, kan worden afgeleid door de compiler omdat List<Integer>#stream()Stream<Integer>we kunnen het ook overslaan, wat ons achterlaat met

    mapToInt(i -> i)
    

Antwoord 3, autoriteit 87%

Naast Commons Lang kun je dit doen met Guava‘s methode Ints.toArray(Collection<Integer> collection):

List<Integer> list = ...
int[] ints = Ints.toArray(list);

Hiermee hoeft u niet de tussenliggende array-conversie uit te voeren die het equivalent van Commons Lang zelf vereist.


Antwoord 4, autoriteit 72%

De eenvoudigste manier om dit te doen is door gebruik te maken van Apache Commons Lang. Het heeft een handige ArrayUtils-klasse die kan doen wat je wilt. Gebruik de toPrimitivemethode met de overbelasting voor een array van Integers.

List<Integer> myList;
 ... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));

Zo hoef je het wiel niet opnieuw uit te vinden. Commons Lang heeft een groot aantal nuttige dingen die Java heeft weggelaten. Hierboven heb ik ervoor gekozen om een ​​Integer-lijst van de juiste maat te maken. U kunt ook een statische Integer-array met een lengte van 0 gebruiken en Java een array van de juiste grootte laten toewijzen:

static final Integer[] NO_INTS = new Integer[0];
   ....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));

Antwoord 5, autoriteit 29%

Java 8heeft ons een gemakkelijke manier gegeven om dit te doen via streams…

Door de functie collections stream()te gebruiken en vervolgens toe te wijzen aan ints, krijg je een IntStream. Met de IntStreamkunnen we toArray() aanroepen wat ons int []

geeft

int [] ints = list.stream().mapToInt(Integer::intValue).toArray();

naar int []

naar IntStream


Antwoord 6, autoriteit 24%

int[] toIntArray(List<Integer> list)  {
    int[] ret = new int[list.size()];
    int i = 0;
    for (Integer e : list)  
        ret[i++] = e;
    return ret;
}

Een kleine wijziging in uw code om dure lijstindexering te voorkomen (aangezien een lijst niet noodzakelijk een ArrayList is, maar een gelinkte lijst kan zijn, waarvoor willekeurige toegang duur is)


Antwoord 7, autoriteit 5%

Hier is Java 8eenregelige code hiervoor

public int[] toIntArray(List<Integer> intList){
       return intList.stream().mapToInt(Integer::intValue).toArray();
}

Antwoord 8, autoriteit 4%

Als u eenvoudig een Integeraan een intkoppelt, moet u overwegen met behulp van parallellisme, aangezien uw toewijzingslogica niet afhankelijk is van variabelen buiten het bereik ervan.

int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();

Wees je hiervan bewust

Houd er rekening mee dat parallellisme niet automatisch sneller is dan het serieel uitvoeren van bewerkingen, hoewel het dat wel kan zijn als je genoeg data en processorcores hebt. Hoewel u met geaggregeerde bewerkingen parallellisme gemakkelijker kunt implementeren, is het nog steeds uw verantwoordelijkheid om te bepalen of uw toepassing geschikt is voor parallellisme.


Er zijn twee manieren om gehele getallen toe te wijzen aan hun primitieve vorm:

  1. Via een ToIntFunction.

    mapToInt(Integer::intValue)
    
  2. Via expliciete unboxingmet lambda-expressie.

    mapToInt(i -> i.intValue())
    
  3. Via impliciete (automatische) unboxing met lambda-expressie.

    mapToInt(i -> i)
    

Gegeven een lijst met een nullwaarde

List<Integer> list = Arrays.asList(1, 2, null, 4, 5);

Hier zijn drie opties om nullte verwerken:

  1. Filter de null-waarden voor het toewijzen.

    int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
    
  2. Wijs de null-waarden toe aan een standaardwaarde.

    int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
    
  3. Verwerk nullbinnen de lambda-expressie.

    int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
    

Antwoord 9, autoriteit 3%

Deze eenvoudige lus is altijd correct! geen fouten

 int[] integers = new int[myList.size()];
  for (int i = 0; i < integers.length; i++) {
      integers[i] = myList.get(i);
  }

Antwoord 10, autoriteit 3%

Ik gooi er nog een in. Ik heb verschillende toepassingen van for-lussen opgemerkt, maar je hebt niet eens iets nodig in de lus. Ik vermeld dit alleen omdat de oorspronkelijke vraag probeerde minder uitgebreide code te vinden.

int[] toArray(List<Integer> list) {
    int[] ret = new int[ list.size() ];
    int i = 0;
    for( Iterator<Integer> it = list.iterator(); 
         it.hasNext(); 
         ret[i++] = it.next() );
    return ret;
}

Als Java meerdere declaraties in een for-lus toestaat zoals C++ dat doet, zouden we een stap verder kunnen gaan en doen for(int i = 0, Iterator it…

Uiteindelijk echter (dit deel is slechts mijn mening), als je een helpende functie of methode wilt hebben om iets voor je te doen, stel het dan gewoon in en vergeet het. Het kan een one-liner of tien zijn; als je er nooit meer naar kijkt, weet je het verschil niet.


Antwoord 11, autoriteit 2%

Er is echt geen manier om “one-lining” te geven aan wat u probeert te doen, omdat toArray een Object[] retourneert en u niet kunt casten van Object[] naar int[] of Integer[] naar int[]


Antwoord 12, autoriteit 2%

int[] ret = new int[list.size()];       
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {       
    ret[i] = iter.next();                
}                                        
return ret;                              

Antwoord 13

probeer ook Dollar(controleer deze revisie):

import static com.humaorie.dollar.Dollar.*
...
List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();

Antwoord 14

Ik raad je aan om de List<?>skeletimplementatie van de Java Collections API te gebruiken, het lijkt in dit specifieke geval heel nuttig te zijn:

package mypackage;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
//Helper method to convert int arrays into Lists
static List<Integer> intArrayAsList(final int[] a) {
    if(a == null)
        throw new NullPointerException();
    return new AbstractList<Integer>() {
        @Override
        public Integer get(int i) {
            return a[i];//autoboxing
        }
        @Override
        public Integer set(int i, Integer val) {
            final int old = a[i];
            a[i] = val;//auto-unboxing
            return old;//autoboxing
        }
        @Override
        public int size() {
            return a.length;
        }
    };
}
public static void main(final String[] args) {
    int[] a = {1, 2, 3, 4, 5};
    Collections.reverse(intArrayAsList(a));
    System.out.println(Arrays.toString(a));
}
}

Pas op voor de nadelen van boksen/unboxen


Antwoord 15

Met Eclipse Collectionskunt u het volgende doen als u een lijst van het type java.util.List<Integer>:

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);

Als je al een Eclipse Collections-type hebt, zoals MutableList, je kunt het volgende doen:

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);

Opmerking: ik ben een toegewijde voor Eclipse Collections


Antwoord 16

Met een lambda zou je dit kunnen doen (compileert in jdk lambda):

public static void main(String ars[]) {
        TransformService transformService = (inputs) -> {
            int[] ints = new int[inputs.size()];
            int i = 0;
            for (Integer element : inputs) {
                ints[ i++ ] = element;
            }
            return ints;
        };
        List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };
        int[] results = transformService.transform(inputs);
    }
    public interface TransformService {
        int[] transform(List<Integer> inputs);
    }

Other episodes