development

목록을 변환하는 방법

big-blog 2020. 2. 10. 22:19
반응형

목록을 변환하는 방법Java에서 int []? [복제]


이것은이 질문과 비슷합니다 : Java에서 int []를 Integer []로 변환하는 방법은 무엇입니까?

Java를 처음 사용합니다. 어떻게는 변환 할 수 있습니다 List<Integer>int[]자바로? List.toArray()실제로 Object[]nether Integer[]또는 로 캐스팅 할 수있는을 반환 하기 때문에 혼란 스럽습니다 int[].

지금은 루프를 사용하여 그렇게하고 있습니다.

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

더 좋은 방법이 있다고 확신합니다.


불행히도 Java가 기본 유형, 복싱, 배열 및 제네릭을 처리하는 특성으로 인해 실제로이 작업을 수행하는 더 좋은 방법 없다고 생각 합니다. 특히:

  • List<T>.toArray에서 Integer변환이 없기 때문에 작동하지 않습니다int
  • 당신은 사용할 수 없습니다 int는 것, 그래서 제네릭 형식 인수로 int- 특정 방법 (또는 더러운 속임수를 수행하는 데 사용되는 반사 하나).

모든 기본 유형에 대해 이러한 종류의 방법의 자동 생성 버전을 가진 라이브러리가 있다고 생각합니다 (즉, 각 유형마다 복사되는 템플릿이 있습니다). 그것은 추악하지만 그것이 내가 두려워하는 방식입니다 :(

짝수하지만 Arrays클래스는 자바에 도착 제네릭 전에 나왔다가 (당신이 원시적 배열을 사용하고자하는 가정) 오늘 소개 된 경우, 여전히 모든 끔찍한 과부하를 포함해야합니다.


Java 8에는 아직 언급 된 스트림이 없으므로 여기에갑니다.

int[] array = list.stream().mapToInt(i->i).toArray();

생각 과정 :

  • simple Stream#toArrayreturns Object[]이므로 원하는 것이 아닙니다. 또한 Stream#toArray(IntFunction<A[]> generator)제네릭 형식이 있기 때문에 우리가 원하는 것을하지 않는 A원시 나타낼 수 없습니다int
  • 따라서 int래퍼 대신 기본 유형을 처리 할 수있는 스트림을 갖는 것이 좋을 것입니다 Integer. 왜냐하면 toArray메소드는 int[]배열 을 반환 할 가능성이 높기 때문에 ( 여기서 Object[]또는 상자 모양의 것을 반환하는 것은 Integer[]부자연 스럽습니다). 다행히도 Java 8에는 이러한 스트림이 있습니다.IntStream
  • 이제 우리가 알아 내야 할 것은 우리 Stream<Integer>( list.stream()그것 에서 반환 될 )를 반짝 로 변환하는 방법 IntStream입니다. 여기에 Stream#mapToInt(ToIntFunction<? super T> mapper)방법이 구출됩니다. 우리가해야 할 일은 그것에서 매핑에 전달됩니다 Integerint. 우리는 다음과 같은 Integer#getValue것을 반환 할 수 있습니다 int:

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

    (또는 누군가가 선호하는 경우 mapToInt(Integer::intValue))

    그러나 컴파일러는이 람다의 결과가 있어야한다는 것을 알고 있기 때문에 unboxing을 사용하여 유사한 코드를 생성 할 수 있습니다 int(lambda는 반환 될 메소드의 본문을 기대 mapToInt하는 ToIntFunction인터페이스의 구현입니다 ).int applyAsInt(T value)int

    그래서 우리는 간단히 쓸 수 있습니다

    mapToInt((Integer i)->i)
    

    또한 Integertype in (Integer i)은 컴파일러에서 유추 할 수 있기 때문에 List<Integer>#stream()반환 Stream<Integer>할 수 있기 때문에 건너 뛸 수 있습니다.

    mapToInt(i -> i)
    

Commons Lang 외에도 Guava 의 방법 으로이 작업을 수행 할 수 있습니다 Ints.toArray(Collection<Integer> collection).

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

이를 통해 Commons Lang과 동등한 중간 배열 변환을 수행 할 필요가 없습니다.


가장 쉬운 방법은 Apache Commons Lang을 사용하는 것입니다 . 그것은 당신이 원하는 것을 할 수있는 편리한 ArrayUtils 클래스를 가지고 있습니다. s toPrimitive배열에 과부하가있는 방법을 사용하십시오 Integer.

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

이렇게하면 바퀴를 재발 명하지 않습니다. Commons Lang은 Java가 빼 놓은 많은 유용한 것들을 가지고 있습니다. 위에서 올바른 크기의 정수 목록을 만들었습니다. 길이가 0 인 정적 정수 배열을 사용하여 Java가 올바른 크기의 배열을 할당하도록 할 수도 있습니다.

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

Java 8 은 스트림을 통해이 작업을 수행하는 쉬운 방법을 제공했습니다 ...

collections stream()함수를 사용하고 int에 매핑하면 IntStream이 생깁니다. IntStreamtoArray ()를 호출하면int []

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

int []

IntStream으로


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

값 비싼 목록 인덱싱을 피하기 위해 코드를 약간 변경하십시오 (List는 반드시 ArrayList가 아니지만 무작위 액세스가 비싼 링크 된 목록 일 수 있기 때문에)


여기에 Java 8 단일 라인 코드가 있습니다.

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

여기에 하나 더 던져 줄 게요. for 루프를 여러 번 사용하는 것을 보았지만 루프 내부에 아무것도 필요하지 않습니다. 원래 질문이 덜 장황한 코드를 찾으려고했기 때문에 이것을 언급했습니다.

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

Java가 for 루프에서 C ++처럼 여러 선언을 허용하면 한 단계 더 나아가 for (int i = 0, Iterator it ...

결국 (이 부분은 제 의견입니다), 당신을 위해 무언가를하는 데 도움이되는 기능이나 방법을 가지려면, 그것을 설정하고 잊어 버려요. 1 개의 라이너 또는 10 개일 수 있습니다. 다시 보지 않으면 차이를 알 수 없습니다.


당신은 단순히 매핑하는 경우 Integer로를 int당신은 고려해야 병렬 처리를 사용 하여 매핑 로직의 범위를 벗어난 변수에 의존하지 않기 때문에.

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

이걸 알아 둬

병렬 처리는 데이터 및 프로세서 코어가 충분한 경우에도 직렬로 작업을 수행하는 것보다 자동으로 빠르지 않습니다. 집계 작업을 통해 병렬 처리를보다 쉽게 ​​구현할 수 있지만 응용 프로그램이 병렬 처리에 적합한 지 결정하는 것은 여전히 ​​귀하의 책임입니다.


정수를 기본 형식으로 맵핑하는 두 가지 방법이 있습니다.

  1. 를 통해 ToIntFunction.

    mapToInt(Integer::intValue)
    
  2. 람다 식의 명시 적 언 박싱통해 .

    mapToInt(i -> i.intValue())
    
  3. 람다 식의 암시 적 (자동) 언 박싱을 통해.

    mapToInt(i -> i)
    

null값이 있는 목록이 주어짐

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

처리 할 옵션은 다음과 같습니다 null.

  1. null매핑하기 전에 값을 필터링하십시오 .

    int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
    
  2. null값을 기본값으로 맵핑하십시오 .

    int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
    
  3. null람다 식 내부를 처리 하십시오.

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

이 간단한 루프는 항상 정확합니다! 버그 없음

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

toArray가 Object []를 리턴하고 Object []에서 int []로 또는 Integer []에서 int []로 캐스트 할 수 없으므로 수행하려는 작업을 "한 줄로 묶는"방법이 없습니다.


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

달러 도보십시오 ( 이 개정판 확인 ) :

import static com.humaorie.dollar.Dollar.*
...

List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();

함께 이클립스 컬렉션 이 유형의 목록이있는 경우, 다음을 수행 할 수 있습니다 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);

이미 Eclipse Collections 유형 MutableList이있는 경우 다음을 수행 할 수 있습니다.

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

참고 : 저는 Eclipse Collections의 커미터입니다.


List<?>java collections API에서 골격 구현 을 사용하는 것이 좋습니다 .이 특별한 경우에는 매우 도움이되는 것으로 보입니다.

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

복싱 / 언 박싱 단점에주의


람다를 사용하면 이렇게 할 수 있습니다 (jdk 람다에서 컴파일).

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

참고 URL : https://stackoverflow.com/questions/960431/how-to-convert-listinteger-to-int-in-java



반응형