Nice programing

Python의 '열거'함수에 해당하는 Java가 있습니까?

nicepro 2020. 11. 18. 21:28
반응형

Python의 '열거'함수에 해당하는 Java가 있습니까?


Python에서이 enumerate함수를 사용하면 (인덱스, 값) 쌍의 시퀀스를 반복 할 수 있습니다. 예를 들면 :

>>> numbers = ["zero", "one", "two"]
>>> for i, s in enumerate(numbers):
...     print i, s
... 
0 zero
1 one
2 two

Java에서 이것을 수행하는 방법이 있습니까?


List인터페이스 를 구현하는 컬렉션의 경우 listIterator()메서드를 호출하여 ListIterator. 이터레이터에는 nextIndex()인덱스를 가져 오는 두 가지 방법이 있습니다 . next(), 값을 가져옵니다 (다른 반복자와 마찬가지로).

따라서 위의 Python에 해당하는 Java는 다음과 같습니다.

List<String> numbers = Arrays.asList("zero", "one", "two");
ListIterator<String> it = numbers.listIterator();
while (it.hasNext()) {
    System.out.println(it.nextIndex() + " " + it.next());
}

Python과 마찬가지로 다음을 출력합니다.

0 zero
1 one
2 two

나는 이것이 파이썬 접근 방식과 가장 유사하다고 생각합니다.

용법

public static void main(String [] args) {
    List<String> strings = Arrays.asList("zero", "one", "two");
    for(EnumeratedItem<String> stringItem : ListUtils.enumerate(strings)) {
        System.out.println(stringItem.index + " " + stringItem.item);
    }
    System.out.println();
    for(EnumeratedItem<String> stringItem : ListUtils.enumerate(strings, 3)) {
        System.out.println(stringItem.index + " " + stringItem.item);
    }
}

산출

0 zero
1 one
2 two

3 zero
4 one
5 two

풍모

  • 반복 가능한 모든 작업
  • 메모리 내 목록 복사본을 만들지 않음 (큰 목록에 적합)
  • 각 구문에 대한 기본 지원
  • 색인에 추가 할 수있는 시작 매개 변수를 허용합니다.

이행

import java.util.Iterator;

public class ListUtils {

    public static class EnumeratedItem<T> {
        public T item;
        public int index;

        private EnumeratedItem(T item, int index) {
            this.item = item;
            this.index = index;
        }
    }

    private static class ListEnumerator<T> implements Iterable<EnumeratedItem<T>> {

        private Iterable<T> target;
        private int start;

        public ListEnumerator(Iterable<T> target, int start) {
            this.target = target;
            this.start = start;
        }

        @Override
        public Iterator<EnumeratedItem<T>> iterator() {
            final Iterator<T> targetIterator = target.iterator();
            return new Iterator<EnumeratedItem<T>>() {

                int index = start;

                @Override
                public boolean hasNext() {
                    return targetIterator.hasNext();
                }

                @Override
                public EnumeratedItem<T> next() {
                    EnumeratedItem<T> nextIndexedItem = new EnumeratedItem<T>(targetIterator.next(), index);
                    index++;
                    return nextIndexedItem;
                }

            };
        }

    }

    public static <T> Iterable<EnumeratedItem<T>> enumerate(Iterable<T> iterable, int start) {
        return new ListEnumerator<T>(iterable, start);
    }

    public static <T> Iterable<EnumeratedItem<T>> enumerate(Iterable<T> iterable) {
        return enumerate(iterable, 0);
    }

}

엄격히 말해서, 파이썬의 enumerate () 함수는 튜플 목록을 반환하고 튜플은 Java에 존재하지 않습니다.

그러나 관심있는 모든 것이 인덱스와 값을 인쇄 하는 것이라면 Richard Fearn의 제안을 따르고 반복기에서 nextIndex () 및 next ()를 사용할 수 있습니다.

또한 enumerate ()는보다 일반적인 zip () 함수 (Python 구문 사용)를 사용하여 정의 할 수 있습니다.

mylist = list("abcd")
zip(range(len(mylist)), mylist)

[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]를 제공합니다.

자신 만의 튜플 클래스를 정의한다면 ( Java에서 쌍 또는 2- 튜플을 시작점으로 사용하기 참조 ), 자바에서 자신의 zip () 함수를 쉽게 작성하여 사용할 수 있습니다 (에 정의 된 Tuple 클래스 사용). 링크):

public static <X,Y> List<Tuple<X,Y>> zip(List<X> list_a, List<Y> list_b) {
    Iterator<X> xiter = list_a.iterator();
    Iterator<Y> yiter = list_b.iterator();

    List<Tuple<X,Y>> result = new LinkedList<Tuple<X,Y>>();

    while (xiter.hasNext() && yiter.hasNext()) {
        result.add(new Tuple<X,Y>(xiter.next(), yiter.next()));
    }

    return result;
}

zip ()이 있으면 enumerate () 구현은 간단합니다.

편집 : 직장에서 느린 하루, 그래서 끝내려면 :

public static <X> List<Tuple<Integer,X>> enumerate (List<X> list_in) {
    List<Integer> nums = new ArrayList<Integer>(list_in.size());
    for (int x = 0; x < list_in.size(); x++) { 
        nums.add(Integer.valueOf(x));
    }

    return zip (nums, list_in);
}

편집 2 :이 질문에 대한 의견에서 지적했듯이 이것은 완전히 동일하지 않습니다. Python의 열거 형과 동일한 값을 생성하지만 Python의 열거 형과 동일한 생성 방식으로 생성하지 않습니다. 따라서 대규모 컬렉션의 경우이 접근 방식은 상당히 금지 될 수 있습니다.


Python 문서 ( here )에 따르면 이것은 Java로 얻을 수있는 가장 가까운 방법이며 더 이상 장황하지 않습니다.

String[] numbers = {"zero", "one", "two"}
for (int i = 0; i < numbers.length; i++) // Note that length is a property of an array, not a function (hence the lack of () )
    System.out.println(i + " " + numbers[i]);
}

List수업 을 이용해야한다면 ...

List<String> numbers = Arrays.asList("zero", "one", "two");
for (int i = 0; i < numbers.size(); i++) {
    System.out.println(i + " " + numbers.get(i));
}

* 참고 : 목록을 순회하면서 목록을 수정해야하는 경우 반복자 개체를 사용해야합니다 ConcurrentModificationException..


List<String> list = { "foo", "bar", "foobar"};
int i = 0;
for (String str : list){
     System.out.println(i++ + str );
}

아니요. 이러한 기능을 지원하는 라이브러리가있을 수 있습니다. 그러나 표준 라이브러리에 의지하면 계산하는 것이 당신의 일입니다.


나는 이것이 매우 복잡하고 비효율적이지만 파이썬 "열거"와 가장 유사한 자바 기능이어야한다고 생각한다. 기본적으로 ListIterator 또는 Collector를 사용하여 목록의 인덱스를 해당 요소에 매핑하기 만하면됩니다.

List<String> list = new LinkedList<>(Arrays.asList("one", "two", "three", "four"));
Map<Integer, String> enumeration = new Map<>();
ListIterator iter = list.listIterator();
while(iter.hasNext){
    map.put(iter.nextIndex(), iter.next());
}

또는 람다 식 사용 :

Set<Integer, String> enumeration = IntStream.range(0, list.size()).boxed.collect(Collectors.toMap(index -> index, index -> list.get(index)));

그런 다음 향상된 for 루프와 함께 사용할 수 있습니다.

for (Map.Entry<Integer, String> entry : enumeration.entrySet){
    System.out.println(entry.getKey() + "\t" + entry.getValue());
}

제네릭을 익명 인터페이스와 결합하면 본질적으로 열거를 처리하기위한 팩토리 메서드를 만들 수 있습니다. Enumerator 콜백은 그 아래에있는 반복자의 혼란을 숨 깁니다.

import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

public class ListUtils2 {
    public static interface Enumerator<T> {
        void execute(int index, T value);
    };

    public static final <T> void enumerate(final List<T> list,
            final Enumerator<T> enumerator) {
        for (ListIterator<T> it = list.listIterator(); it.hasNext();) {
            enumerator.execute(it.nextIndex(), it.next());
        }
    }

    public static final void enumerate(final String[] arr,
            final Enumerator<String> enumerator) {
        enumerate(Arrays.asList(arr), enumerator);
    }

    public static void main(String[] args) {
        String[] names = { "John", "Paul", "George", "Ringo" };

        enumerate(names, new Enumerator<String>() {
            @Override
            public void execute(int index, String value) {
                System.out.printf("[%d] %s%n", index, value);
            }
        });
    }
}

결과

[0] John
[1] Paul
[2] George
[3] Ringo

확장 된 생각

지도, 축소, 필터링

한 단계 더 나아가이 개념을 기반으로지도, 축소 및 필터링 기능을 만들었습니다.

Google의 GuavaApache 공통 컬렉션 종속성에는 유사한 기능이 포함됩니다. 원하는대로 확인할 수 있습니다.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

public class ListUtils {
    // =========================================================================
    // Enumerate
    // =========================================================================
    public static abstract interface Enumerator<T> {
        void execute(int index, T value, List<T> list);
    };

    public static final <T> void enumerate(final List<T> list,
            final Enumerator<T> enumerator) {
        for (ListIterator<T> it = list.listIterator(); it.hasNext();) {
            enumerator.execute(it.nextIndex(), it.next(), list);
        }
    }

    // =========================================================================
    // Map
    // =========================================================================
    public static interface Transformer<T, U> {
        U execute(int index, T value, List<T> list);
    };

    public static final <T, U> List<U> transform(final List<T> list,
            final Transformer<T, U> transformer) {
        List<U> result = new ArrayList<U>();
        for (ListIterator<T> it = list.listIterator(); it.hasNext();) {
            result.add(transformer.execute(it.nextIndex(), it.next(), list));
        }
        return result;
    }

    // =========================================================================
    // Reduce
    // =========================================================================
    public static interface Reducer<T, U> {
        U execute(int index, T value, U result, List<T> list);
    };

    public static final <T, U> U reduce(final List<T> list,
            final Reducer<T, U> enumerator, U result) {
        for (ListIterator<T> it = list.listIterator(); it.hasNext();) {
            result = enumerator.execute(it.nextIndex(), it.next(), result, list);
        }
        return result;
    }

    // =========================================================================
    // Filter
    // =========================================================================
    public static interface Predicate<T> {
        boolean execute(int index, T value, List<T> list);
    };

    public static final <T> List<T> filter(final List<T> list,
            final Predicate<T> predicate) {
        List<T> result = new ArrayList<T>();
        for (ListIterator<T> it = list.listIterator(); it.hasNext();) {
            int index = it.nextIndex();
            T value = it.next();
            if (predicate.execute(index, value, list)) {
                result.add(value);
            }
        }
        return result;
    }

    // =========================================================================
    // Predefined Methods
    // =========================================================================
    // Enumerate
    public static <T> String printTuples(List<T> list) {
        StringBuffer buff = new StringBuffer();

        enumerate(list, new Enumerator<T>() {
            @Override
            public void execute(int index, T value, List<T> list) {
                buff.append('(').append(index).append(", ")
                    .append(value).append(')');
                if (index < list.size() - 1) {
                    buff.append(", ");
                }
            }
        });

        return buff.toString();
    }

    // Map
    public static List<String> intToHex(List<Integer> list) {
        return transform(list, new Transformer<Integer, String>() {
            @Override
            public String execute(int index, Integer value, List<Integer> list) {
                return String.format("0x%02X", value);
            }
        });
    }

    // Reduce
    public static Integer sum(List<Integer> list) {
        return reduce(list, new Reducer<Integer, Integer>() {
            @Override
            public Integer execute(int index, Integer value, Integer result,
                    List<Integer> list) {
                return result + value;
            }
        }, 0);
    }

    // Filter
    public static List<Integer> evenNumbers(List<Integer> list) {
        return filter(list, new Predicate<Integer>() {
            @Override
            public boolean execute(int index, Integer value, List<Integer> list) {
                return value % 2 == 0;
            }
        });
    }

    // =========================================================================
    // Driver
    // =========================================================================
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(8, 6, 7, 5, 3, 0, 9);

        // Enumerate
        System.out.printf("%-10s: %s%n", "Enumerate", printTuples(numbers));

        // Map
        System.out.printf("%-10s: %s%n", "Map", intToHex(numbers));

        // Reduce
        System.out.printf("%-10s: %d%n", "Reduce", sum(numbers));

        // Filter
        System.out.printf("%-10s: %s%n", "Filter", evenNumbers(numbers));
    }
}

이제 Java 8s Stream API와 함께 작은 ProtonPack라이브러리를 제공 StreamUtils하여 쉽게 달성 할 수 있습니다.

첫 번째 예는 질문에서와 동일한 for-each 표기법을 사용합니다.

Stream<String> numbers = Arrays.stream("zero one two".split(" "));
List<Indexed<String>> indexedNumbers = StreamUtils.zipWithIndex(numbers)
                                                  .collect(Collectors.toList());
for (Indexed<String> indexed : indexedNumbers) {
    System.out.println(indexed.getIndex() + " " + indexed.getValue());
}

위는 파이썬 에서처럼 게으른 평가를 제공하지 않지만. 이를 위해 forEach()Stream API 메서드를 사용해야합니다 .

Stream<String> numbers = Arrays.stream("zero one two".split(" "));
StreamUtils.zipWithIndex(numbers)
        .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));

지연 평가는 다음 무한 스트림으로 확인할 수 있습니다.

Stream<Integer> infStream = Stream.iterate(0, i -> i++);
StreamUtils.zipWithIndex(infStream)
        .limit(196)
        .forEach(n -> System.out.println(n.getIndex() + " " + n.getValue()));

간단하고 직관적

public static <T> void enumerate(Iterable<T> iterable, java.util.function.ObjIntConsumer<T> consumer) {
    int i = 0;
    for(T object : iterable) {
        consumer.accept(object, i);
        i++;
    }
}

샘플 사용법 :

void testEnumerate() {
    List<String> strings = Arrays.asList("foo", "bar", "baz");
    enumerate(strings, (str, i) -> {
        System.out.println(String.format("Index:%d String:%s", i, str));
    });
}

참고 URL : https://stackoverflow.com/questions/7167253/is-there-a-java-equivalent-of-pythons-enumerate-function

반응형