Преобразование Java-массива в Iterable

У меня есть массив примитивов, например, для 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)

Наконец, поскольку, похоже, есть домашнее задание об этом, избегайте публикации домашнего кода.

Ответ 1

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>

Ответ 2

только мои 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.");
            }
        };
    }
};

Ответ 3

В Guava предусмотрен адаптер, который вы хотите как 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-элементный список массивов, содержащий ваш массив.

Ответ 4

С помощью 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();

Ответ 5

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

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

Итератор сам является ленивым UnmodifiableIterator, но это именно то, что мне нужно.

Ответ 6

Вы можете использовать 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"
);

Ответ 7

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

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

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

→ Этот подход является перформативным и сохраняет вашу память (за исключением памяти только что созданных методов, хотя использование Arrays.asList() будет принимать память одинаковым образом)

2) Поскольку массивы не имеют методов (чтобы их можно было прочитать на стороне, которую вы связали), они также не могут предоставить экземпляр Iterator. Если вы действительно слишком ленивы, чтобы писать новые классы, вы должны использовать экземпляр уже существующего класса, который реализует Iterable, потому что нет другого пути, кроме создания экземпляра Iterable или подтипа.
Единственный способ создания существующей производной Collection, использующей Iterable, - использовать цикл (за исключением использования анонимных классов, как описано выше), или вы создаете экземпляр класса Iterable, конструктор которого позволяет массив примитивного типа (поскольку Object[] doesn 't позволяют массивы с примитивными типами элементов), но, насколько я знаю, Java API не имеет такого класса.

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

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

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

Ответ 8

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

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

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