Вопрос по java, arrays – Конвертировать массив Java в Iterable

117

У меня есть массив примитивов, например для int, int [] foo. Это может быть маленький размер или нет.

int foo[] = {1,2,3,4,5,6,7,8,9,0};

Каков наилучший способ создатьIterable<Integer> от него?

Iterable<Integer> fooBar = convert(foo);

Заметки:

Пожалуйста, не отвечайте, используя циклы (если вы не можете дать хорошее объяснение того, как компилятор делает что-то умное с ними?)

Также обратите внимание, что

int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);

Даже не скомпилирует

Type mismatch: cannot convert from List<int[]> to List<Integer>

Также проверьте Почему массив нельзя присвоить Iterable? прежде чем ответить.

Кроме того, если вы используете какую-то библиотеку (например, Guava), пожалуйста, объясните, почему это Лучшая. (Потому что это от Google не полный ответ: P)

И последнее, так как кажется, что это домашнее задание, не размещайте домашний код.

возможный дубликатIterator for array NPE
Добавьте их в LinkedList, а затем просто верните итератор этого набора. user1181445

Ваш Ответ

9   ответов
3

Прежде всего, я могу только согласиться, чтоArrays.asList(T...) Ясно, что это лучшее решение для типов Wrapper или массивов с непримитивными типами данных. Этот метод вызывает конструктор простой приватной статикиAbstractList реализация вArrays Класс, который в основном сохраняет заданную ссылку на массив как поле и имитирует список, переопределяя необходимые методы.

Если вы можете выбирать между типом примитива или типом Wrapper для вашего массива, я бы использовал тип Wrapper для таких ситуаций, но, конечно, это не всегда полезно или необходимо. Вы можете сделать только две возможности:

1) Вы можете создать класс со статическим методом для каждого массива примитивных типов данных (boolean, byte, short, int, long, char, float, double возвращаяIterable<WrapperType>, Эти методы будут использовать анонимные классыIterator (Кроме тогоIterable) которые могут содержать ссылку на аргумент включающего метода (например,int[]) как поле для реализации методов.

-> This approach is performant and saves you memory (except for the memory of the newly created methods, even though, using Arrays.asList() would take memory in the same way)

2) Поскольку у массивов нет методов (которые будут прочитаны на стороне, с которой вы связаны), они не могут обеспечитьIterator экземпляр тоже. Если вам действительно лень писать новые классы, вы должны использовать экземпляр уже существующего класса, который реализуетIterable потому что нет другого пути, чем создание экземпляраIterable или подтип.
ЕДИНСТВЕННЫЙ способ создания существующей коллекции производной реализацииIterable использовать цикл (за исключением того, что вы используете анонимные классы, как описано выше) или вы создаетеIterable реализующий класс, конструктор которого допускает массив примитивных типов (потому чтоObject[] не разрешает массивы с элементами примитивного типа), но, насколько мне известно, Java API не имеет такого класса.

Причину цикла можно легко объяснить:
для каждой коллекции вам нужны объекты, а типы первичных данных не являются объектами. Объекты намного больше, чем примитивные типы, поэтому им требуются дополнительные данные, которые должны быть сгенерированы для каждого элемента массива примитивных типов. Это означает, что если два способа из трех (используяArrays.asList(T...) или используя существующую коллекцию) требуется совокупность объектов, которые необходимо создать для каждого примитивного значения вашегоint[] массив объект-обертка. Третий способ - использовать массив как есть и использовать его в анонимном классе, так как я думаю, что он предпочтителен из-за высокой производительности.

Существует также третья стратегия, использующаяObject в качестве аргумента для метода, где вы хотите использовать массив илиIterable и это потребовало бы проверок типов, чтобы выяснить, какой тип имеет аргумент, однако я бы вообще не рекомендовал его, поскольку вам обычно нужно учитывать, что объект не всегда имеет требуемый тип и что для определенных случаев вам нужен отдельный код.

В заключение, это ошибка проблемной системы универсальных типов Java, которая не позволяет использовать примитивные типы в качестве универсального типа, который мог бы сэкономить много кода, просто используяArrays.asList(T...), Таким образом, вам нужно запрограммировать для каждого массива примитивного типа, вам нужен такой метод (который в принципе не имеет значения для памяти, используемой программой C ++, которая создаст для каждого используемого аргумента типа отдельный метод).

25

С Java 8 вы можете сделать это.

final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();
98
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

List<Integer> list = Arrays.asList(foo);
// or
Iterable<Integer> iterable = Arrays.asList(foo);

Хотя вам нужно использоватьInteger массив (неint массив), чтобы это работало.

Для примитивов вы можете использовать guava:

Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>15.0</version>
    <type>jar</type>
</dependency>

Для Java8: (из ответа Джин Квона)

final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();
Две заметки: 1) у него естьintнеInteger 2) List ужеIterable так что третья строка бессмысленна.
2-я и 3-я строки - варианты, я бы сказал :)
Значит вторая строка бессмысленна тогда? ;)
ему нужен Iterable, поэтому есть третья строка.
Это не часть домашней работы, я просто пытался избежать дублирования кода для функции отладки, обрабатывающей содержимое массива или списка ... Осматривая, я действительно нашел Arrays.asList (..) ;, но по крайней мере Eclipse, похоже, думает, что он не будет делать то, что я хочу (например, он выводит результат Arrays.asList (foo) как List & lt; int [] & gt ;, а не List & lt; Integer & gt; ...) Я нашел это достаточно интересным для вопрос ... (комментируя частями причину ограничений-) ntg
40

только мои 2 цента:

final int a[] = {1,2,3};

java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() {

    public Iterator<Integer> iterator() {
       return new Iterator<Integer>() {
            private int pos=0;

            public boolean hasNext() {
               return a.length>pos;
            }

            public Integer next() {
               return a[pos++];
            }

            public void remove() {
                throw new UnsupportedOperationException("Cannot remove an element of an array.");
            }
        };
    }
};
remove () не является необходимым в Java 8, потому что это метод по умолчанию, который выбрасывает UnsupportedOperationException. Только если вы хотите предоставить лучшее объяснение сообщения.
+1 я делаю что-то похожее, чтобы создатьIterator<Character> изString, Реализация своегоIterator Кажется, это единственный способ избежать ненужной итерации всех значений для преобразования из типа объекта в тип примитива (через Guava).Ints.asList() например), просто чтобы иметь возможность получитьIterator отList это было создано.
Ты прав, Алекс. Методы по умолчанию были добавлены в Java 8. В 2013 году я добавил этот древний кусок кода здесь.
-2

В java8 поток IntSteam может быть упакован в поток целых чисел.

public static Iterable<Integer> toIterable(int[] ints) {
    return IntStream.of(ints).boxed().collect(Collectors.toList());
}

Я думаю, что производительность имеет значение в зависимости от размера массива.

4

Ты можешь использоватьIterableOf отCactoos:

Iterable<String> names = new IterableOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);

Затем вы можете превратить его в список, используяListOf:

List<String> names = new ListOf<>(
  new IterableOf<>(
    "Scott Fitzgerald", "Fyodor Dostoyevsky"
  )
);

Или просто так:

List<String> names = new ListOf<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);
20

Гуава предоставляет адаптер, который вы хотите, какInt.asList (), Существует эквивалент для каждого типа примитива в связанном классе, например,Booleans заboolean, так далее.

int foo[] = {1,2,3,4,5,6,7,8,9,0};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
    System.out.println(i);
}

Предложения выше, чтобы использоватьArrays.asList не будет работать, даже если они компилируются, потому что вы получаетеIterator<int[]> скорее, чемIterator<Integer>, В результате получается, что вместо создания списка, поддерживаемого вашим массивом, вы создали 1-элементный список массивов, содержащий ваш массив.

8

У меня была такая же проблема, и я решил ее так:

final YourType[] yourArray = ...;
return new Iterable<YourType>() {
  public Iterator<YourType> iterator() {
     return Iterators.forArray(yourArray);   // Iterators is a Google guava utility
  }
}

Сам итератор ленивыйUnmodifiableIterator но это именно то, что мне было нужно.

1

Хотя аналогичный ответ уже был опубликован, я думаю, что причина использования нового PrimitiveIterator.OfInt не ясна. Хорошее решение состоит в том, чтобы использовать Java 8 PrimitiveIterator, поскольку он специализируется на примитивных типах int (и избегает дополнительных штрафов за упаковку / распаковку):

    int[] arr = {1,2,3};
    // If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
    PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
    while (iterator.hasNext()) {
        System.out.println(iterator.nextInt());
        // Use nextInt() instead of next() here to avoid extra boxing penalty
    }

Ref:https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html

Похожие вопросы