Dart'ta dizin ve değer içeren bir liste aracılığıyla numaralandırma veya eşleme


94

Dartta ortak olanın herhangi bir eşdeğeri var:

enumerate(List) -> Iterator((index, value) => f)
or 
List.enumerate()  -> Iterator((index, value) => f)
or 
List.map() -> Iterator((index, value) => f)

Görünüşe göre bu en kolay yol, ancak bu işlevselliğin var olmaması yine de garip görünüyor.

Iterable<int>.generate(list.length).forEach( (index) => {
  newList.add(list[index], index)
});

Düzenle:

@ Hemanth-raj sayesinde aradığım çözümü bulabildim. Bunu benzer bir şey yapması gereken herkes için buraya koyacağım.

List<Widget> _buildWidgets(List<Object> list) {
    return list
        .asMap()
        .map((index, value) =>
            MapEntry(index, _buildWidget(index, value)))
        .values
        .toList();
}

Alternatif olarak, yinelenebilir bir döndürmek için bir eşzamanlı oluşturucu işlevi oluşturabilirsiniz.

Iterable<MapEntry<int, T>> enumerate<T>(Iterable<T> items) sync* {
  int index = 0;
  for (T item in items) {
    yield MapEntry(index, item);
    index = index + 1;
  }
}

//and use it like this.
var list = enumerate([0,1,3]).map((entry) => Text("index: ${entry.key}, value: ${entry.value}"));

Map#forEach? istediğin bu mu
pskink

Harita Değil Liste aracılığıyla
David Rees

Map # forEach bir List? ne demek istiyorsun? dokümanlar şöyle der: "Haritanın her anahtar / değer çiftine f uygulanır. f'nin çağrılması, haritadan anahtar eklememeli veya kaldırmamalıdır."
pskink

Ayrıca "indeks ve değer içeren bir liste aracılığıyla numaralandırma veya haritalama" ile ne demek istediğini anlamıyorum
Günter Zöchbauer

Yanıtlar:


143

asMapListeyi anahtarların indeks ve değerlerin indekste eleman olduğu bir haritaya dönüştüren bir yöntem vardır. Docs bakmak Lütfen burada .

Misal:

List _sample = ['a','b','c'];
_sample.asMap().forEach((index, value) => f);

Bu yardımcı olur umarım!


34

Yineleme indeksini almak için yerleşik bir işlev yoktur.

Eğer benim gibi Mapbasit bir indeks için bir (veri yapısı) oluşturma fikrinden hoşlanmıyorsanız, muhtemelen istediğiniz şey mapsize indeksi veren bir fonksiyondur. Hadi diyelim mapIndexed(Kotlin'deki gibi):

children: mapIndexed(
  list,
  (index, item) => Text("event_$index")
).toList();

Uygulaması mapIndexedbasittir:

Iterable<E> mapIndexed<E, T>(
    Iterable<T> items, E Function(int index, T item) f) sync* {
  var index = 0;

  for (final item in items) {
    yield f(index, item);
    index = index + 1;
  }
}

1
Bu iyi bir cevap, ancak muhtemelen eşzamanlı bir jeneratör olarak yazılması daha iyi olacaktır
David Rees

2
@DavidRees öneri için teşekkürler! Ayrıca işlevi yeniden adlandırdımmapIndexed
Vivien

Dartın bunu yapmak için yerleşik bir kolay yolu olmaması çok yazık. 30 yaşındaki python bile bunu kolayca yapabilir!
osamu

Bunun .asMap().forEach()aslında bununla aynı olduğu ortaya çıktı - cevabıma bakın.
Timmmm

1
@Timmmm asMap()Verileri almak için ek döngüye mal olacağını düşünüyorum , bu nedenle mapIndexed()yukarıdaki gibi verimli olmayacak .
anticafe

17

@Hemanth Raj cevabına dayalı olarak.

Geri dönüştürmek için yapabilirdin

List<String> _sample = ['a', 'b', 'c'];
_sample.asMap().values.toList(); 
//returns ['a', 'b', 'c'];

Veya bir eşleme işlevi için dizine ihtiyacınız varsa, bunu yapabilirsiniz:

_sample
.asMap()
.map((index, str) => MapEntry(index, str + index.toString()))
.values
.toList();
// returns ['a0', 'b1', 'c2']

14

Dart 2.7 ile başlayarak, yardımcı yöntemler yazmak yerine extensionişlevleri genişletmek için kullanabilirsiniz .Iterable

extension ExtendedIterable<E> on Iterable<E> {
  /// Like Iterable<T>.map but callback have index as second argument
  Iterable<T> mapIndex<T>(T f(E e, int i)) {
    var i = 0;
    return this.map((e) => f(e, i++));
  }

  void forEachIndex(void f(E e, int i)) {
    var i = 0;
    this.forEach((e) => f(e, i++));
  }
}

Kullanım:

final inputs = ['a', 'b', 'c', 'd', 'e', 'f'];
final results = inputs
  .mapIndex((e, i) => 'item: $e, index: $i')
  .toList()
  .join('\n');

print(results);

// item: a, index: 0
// item: b, index: 1
// item: c, index: 2
// item: d, index: 3
// item: e, index: 4
// item: f, index: 5
inputs.forEachIndex((e, i) => print('item: $e, index: $i'));

// item: a, index: 0
// item: b, index: 1
// item: c, index: 2
// item: d, index: 3
// item: e, index: 4
// item: f, index: 5

1
bu en iyi cevaptır, bu sadece String'i değil Widget'ları da döndürebileceğiniz Flutter öğeleriyle bile çalışır.
STEEL

7

Lukas Renggli'nin daha fazla paketi, tam olarak istediğinizi yapan 'indeksli' dahil olmak üzere birçok yararlı araç içerir. Dokümanlardan:

indexed(['a', 'b'], offset: 1)
  .map((each) => '${each.index}: ${each.value}')
  .join(', ');

(Smalltalk arka planınız yoksa, uzaklık argümanını göz ardı edebilirsiniz :-).


6

Başlangıçta ['one', 'two', 'three'].asMap().forEach((index, value) { ... });gerçekten verimsiz olacağını düşündüm çünkü listeyi haritaya dönüştürüyormuş gibi görünüyor. Aslında öyle değil - dokümantasyon , listenin değişmez bir görünümünü oluşturduğunu söylüyor . dart2jsBu kodu iki kez kontrol ettim :

void main() {
  final foo = ['one', 'two', 'three'];
  foo.asMap().forEach((idx, val) {
    print('$idx: $val');
  });
}

Çok fazla kod üretir ! Ancak işin özü şudur:

  main: function() {
    var foo = H.setRuntimeTypeInfo(["one", "two", "three"], ...);
    new H.ListMapView(foo, ...).forEach$1(0, new F.main_closure());
  },

  H.ListMapView.prototype = {
    forEach$1: function(_, f) {
      var t1, $length, t2, i;
      ...
      t1 = this._values;
      $length = t1.length;
      for (t2 = $length, i = 0; i < $length; ++i) {
        if (i >= t2)
          return H.ioore(t1, i);
        f.call$2(i, t1[i]);
        t2 = t1.length;
        if ($length !== t2)
          throw H.wrapException(P.ConcurrentModificationError$(t1));
      }
    },
    ...
  },

  F.main_closure.prototype = {
    call$2: function(idx, val) {
      ...
      H.printString("" + idx + ": " + H.S(val));
    },
    $signature: 1
  };

Yani verimli olanı yapacak kadar akıllı! Oldukça zekice.

Elbette normal bir for döngüsü de kullanabilirsiniz:

for (var index = 0; index < values.length; ++index) {
  final value = values[index];

4

Kolaylık sağlamak için bu uzatma yöntemini kullanabilirsiniz.

extension CollectionUtil<T> on Iterable<T>  {

  Iterable<E> mapIndexed<E, T>(E Function(int index, T item) transform) sync* {
    var index = 0;

    for (final item in this) {
      yield transform(index, item as T);
      index++;
    }
  }
}

2

Listeyi önce haritaya dönüştürmek için asMap kullanın . Öğenin dizini anahtardır. Öğe değer olur. Anahtarı ve değeri istediğiniz herhangi bir şeye eşlemek için girişleri kullanın .

List rawList = ["a", "b", "c"];
List<String> argList = rawList.asMap().entries.map((e) => '${e.key}:${e.value}').toList();
print(argList);

Çıktı:

[0:a, 1:b, 2:c]
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.