Java Dizisini Yinelenebilir Olarak Dönüştür


150

Bir ilkel dizim var, örneğin int, int [] foo. Küçük boyutlu olabilir ya da olmayabilir.

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

Ondan bir oluşturmanın en iyi yolu nedir Iterable<Integer>?

Iterable<Integer> fooBar = convert(foo);

Notlar:

Lütfen döngüler kullanarak cevap vermeyin (derleyicinin onlar hakkında nasıl akıllıca bir şey yaptığını iyi bir şekilde açıklayamadıkça?)

Ayrıca şunu da unutmayın

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

Derlenmeyecek bile

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

Ayrıca bir dizi neden Yinelenebilir'e atanamıyor? cevaplamadan önce.

Ayrıca, bir kütüphane (örn., Guava) kullanıyorsanız, lütfen bunun neden En İyi olduğunu açıklayın. (Çünkü Google'dan gelen tam bir cevap değildir: P)

Son olarak, bu konuda bir ödev olduğu için, ödev kodu yazmaktan kaçının.



Bunları bir LinkedList'e ekleyin, sonra sadece bu Setin yineleyicisini döndürün.

Yanıtlar:


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

Ancak bunun çalışması için bir Integerdizi (dizi değil int) kullanmanız gerekir .

İlkel için guava kullanabilirsiniz:

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

Java8 için: (Jin Kwon'un cevabından)

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

10
İki not: 1) var int, Integer2 değil ) Listzaten Iterableüçüncü satır anlamsız.
maksimov

1
Üçüncü satırın olmasının sebebi yinelenebilir.
fmucar

5
2. ve 3. satırlar diyeceğim seçeneklerdir :)
fmucar

1
Bu bir ödevin bir parçası değil, ben sadece bir dizi veya liste içeriğini işleme hata ayıklama fonksiyonu için kod çoğaltma önlemek için çalışıyordu ... Etrafa bakarken gerçekten Arrays.asList (..);, ama en azından buldum Tutulma istediğimi yapmayacağını düşünüyor gibi görünüyor (örneğin, Arrays.asList (foo) sonucunu Liste <int []> değil, Liste <Integer> ... soru ... (-Sınırların nedeni parçalarda kırıcı yorum-)
ntg

1
Genel olarak, bunu yapmanın birçok yolu düşünebilirdim, ama en iyisinin ne olduğunu merak ediyordum (örneğin bir döngü, lapaya göre daha yavaş olur ... {şey, sorun, hiçbir şey düşünemiyorum !: )}) Ayrıca nedenim, sorum neden olmasa da, nasıl ve ne tür bir konteynerin en iyi olacağı hakkında bir tartışma için stackoverflow.com/questions/1160081/… ' a bakın (neden ArrayList? Generics kullanarak sarıcı .., Muhtemelen boyutuna bağlıdır ...)
ntg

44

sadece 2 sentim:

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

9
remove () java 8'de gerekli değildir, çünkü UnsupportedOperationException öğesini atan varsayılan bir yöntemdir. Sadece daha iyi bir açıklama mesajı vermek istiyorsanız.
Alex

+1 Iterator<Character>a 'dan oluşturmak için benzer bir şey yapıyorum String. Kendi Uygulanması Iterator(Guava en aracılığı ilkel tipine nesne türünden dönüştürmek için tüm değerleri yineleme gereksiz önlemenin tek yolu gibi görünüyor Ints.asList()sadece bir elde edebilmek için, örneğin) Iteratordan Listyaratıldığı ortaya çıkıyor.
spaaarky21

2
Haklısın Alex. Varsayılan yöntemler Java 8'e eklendi. 2013'te bu eski kod parçasını buraya ekledim.
Joerg Ruethschilling

29

Java 8 ile bunu yapabilirsiniz.

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

20

Guava, Int.asList () olarak istediğiniz adaptörü sağlar . İlişkili sınıftaki her ilkel tür Booleansiçin boolean, örneğin , vb. İçin bir eşdeğer vardır .

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

Kullanımına Yukarıdaki öneriler Arrays.asListdeğil iş, onlar derlemek bile bir alacak çünkü Iterator<int[]>ziyade Iterator<Integer>. Olan şey, diziniz tarafından desteklenen bir liste oluşturmak yerine dizinizi içeren 1 öğeli diziler listesi oluşturmuş olmanızdır.


sadece bir not: bağlantı artık çalışmıyor. Github bağlantısı: github.com/google/guava/blob/master/guava/src/com/google/common/…
Orangle

Teşekkürler @Passi, düzeltildi (artık javadoc'a bağlantı vermek için Google'ın desteklediği bir yol bulamıyorum, bu nedenle sağladığınız kaynağa bağlandım).
BeeOnRope

8

Ben aynı sorunu vardı ve böyle çözdü:

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

Yineleyici kendisi bir tembel UnmodifiableIteratorama tam olarak ne gerekli.


7

Java 8 veya sonraki sürümlerde, Iterablefonksiyonel bir arayüz döner Iterator. Böylece bunu yapabilirsiniz.

int[] array = {1, 2, 3};
Iterable<Integer> iterable = () -> Arrays.stream(array).iterator();
for (int i : iterable)
    System.out.println(i);

->

1
2
3

3

Her şeyden önce, sadece Arrays.asList(T...)Wrapper türleri veya ilkel olmayan veri tiplerine sahip diziler için açıkça en iyi çözüm olduğunu kabul edebilirim . Bu yöntem AbstractList, Arraystemelde verilen dizi başvurusunu alan olarak kaydeden ve gerekli yöntemleri geçersiz kılarak bir listeyi simüle eden basit bir özel statik uygulamanın yapıcısını çağırır .

Diziniz için ilkel bir tür veya bir Wrapper türü arasında seçim yapabiliyorsanız, bu tür durumlar için Wrapper türünü kullanırım, ancak elbette, her zaman yararlı veya gerekli değildir. Yapabileceğiniz sadece iki olasılık vardır:

1) Her bir ilkel veri türü dizisi için statik yöntemli bir sınıf oluşturabilirsiniz ( boolean, byte, short, int, long, char, float, doublebir Iterable<WrapperType döndürerek >. Bu yöntemler Iterator(Iterable) int[], yöntemlerin uygulanması için , içerme yönteminin argümanının (örneğin an ) alan olarak referansını içermesine izin verilir .

-> Bu yaklaşım performans gösterir ve size bellek kazandırır (yeni oluşturulan yöntemlerin Arrays.asList()belleği dışında, aynı şekilde bellek kullanmasına rağmen )

2) Dizilerin yöntemleri olmadığı için (yan tarafta okunacak şekilde) bağlandınız) da bir Iteratorörnek sunamazlar. Gerçekten yeni sınıflar yazmak için çok tembelseniz, zaten var olan bir sınıfın örneğini kullanmanız gerekir, Iterableçünkü örnekleme Iterableveya alt türden başka bir yol yoktur .
Mevcut bir Koleksiyon türevi uygulamasını oluşturmanın SADECE yoluIterablebir döngü kullanmaktır (yukarıda açıklandığı gibi anonim sınıflar kullanmanız dışında) veya Iterableyapıcısı ilkel tür dizisine izin verdiği için ( Object[]ilkel tür öğelerine sahip dizilere izin vermediğinden) ancak bildiğim kadarıyla Java API'sı uygulayan bir sınıf oluşturursunuz. böyle bir sınıfa sahip değil.

Döngünün nedeni kolayca açıklanabilir:
Her Koleksiyon için ihtiyacınız olan Nesneler ve ilkel veri türleri nesne değildir. Nesneler, ilkel türlerden çok daha büyük olduğundan, ilkel tür dizisinin her öğesi için oluşturulması gereken ek veriler gerektirir. Bu, üç yoldan ( Arrays.asList(T...)mevcut bir Koleksiyonu kullanmak veya kullanmak) iki nesne nesnesi gerektiriyorsa, cihazınızın her ilkel değeri içinint[]sarma nesnesini sıralayın. Üçüncü yol, diziyi olduğu gibi kullanır ve hızlı performans nedeniyle tercih edildiğini düşündüğüm için anonim bir sınıfta kullanır. Diziyi kullanmak istediğiniz yöntem için as bağımsız değişkeni

kullanan üçüncü bir strateji de vardır Objectveya Iterablebağımsız değişkenin hangi tür olduğunu anlamak için tür denetimleri gerektirir, ancak genellikle ihtiyacınız olduğu gibi hiç tavsiye etmem Nesnenin her zaman gerekli tipte olmadığını ve belirli durumlar için ayrı bir koda ihtiyacınız olduğunu düşünün.

Sonuç olarak, Java'nın ilkel türlerin genel tür olarak kullanılmasına izin vermeyen sorunlu Genel Tür sisteminin hatası,Arrays.asList(T...). Bu nedenle, her bir ilkel tür dizisi için programlamanız gerekir, böyle bir yönteme ihtiyacınız vardır (bu, temel olarak bir C ++ programı tarafından kullanılan bellekte kullanılan ve her kullanılan tür bağımsız değişkeni için ayrı bir yöntem oluşturacak olan bellekte fark yaratmaz.


3

Sen kullanabilirsiniz IterableOfgelen Cactoos :

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

Ardından, aşağıdakileri kullanarak bir listeye dönüştürebilirsiniz ListOf:

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

Veya sadece bu:

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

1

Benzer bir cevap zaten yayınlanmış olsa da, yeni PrimitiveIterator.OfInt kullanmak için neden açık değildi düşünüyorum. İlkel int türleri için özel olduğundan (ve fazladan boks / kutudan çıkarma cezasını önlediğinden) Java 8 PrimitiveIterator'ı kullanmak iyi bir çözümdür:

    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


-2

Java8'de IntSteam akışı, Tamsayıların akışı için kutulanmış olabilir.

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

Bence performans dizinin boyutuna göre önemli.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.