แจกแจงหรือแมปผ่านรายการที่มีดัชนีและค่าใน Dart


95

ในโผมีสิ่งที่เทียบเท่ากับทั่วไป:

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

ดูเหมือนว่านี่จะเป็นวิธีที่ง่ายที่สุด แต่ก็ยังแปลกที่ฟังก์ชันนี้จะไม่มีอยู่จริง

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

แก้ไข:

ขอบคุณ @ hemanth-raj ที่ฉันสามารถหาวิธีแก้ปัญหาที่ฉันกำลังมองหา ฉันจะใส่ไว้ตรงนี้สำหรับใครก็ตามที่ต้องการทำอะไรคล้าย ๆ กัน

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

หรือคุณสามารถสร้างฟังก์ชันเครื่องกำเนิดไฟฟ้าแบบซิงโครนัสเพื่อส่งคืนค่าที่ทำซ้ำได้

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เหรอ? เป็นสิ่งที่คุณต้องการหรือไม่?
pskink

มันแจกแจงผ่าน List not a Map
David Rees

Map # forEachแจกแจงผ่าน a List? คุณหมายถึงอะไร? เอกสารกล่าวว่า: "ใช้ f กับคู่คีย์ / ค่าแต่ละคู่ของแผนที่การเรียก f จะต้องไม่เพิ่มหรือลบคีย์ออกจากแผนที่"
pskink

ฉันไม่เข้าใจว่าคุณหมายถึงอะไรด้วย "แจงนับหรือทำแผนที่ผ่านรายการที่มีดัชนีและค่า"
GünterZöchbauer

คำตอบ:


145

มีasMapวิธีการที่แปลงรายการเป็นแผนที่โดยที่คีย์เป็นดัชนีและค่าเป็นองค์ประกอบที่ดัชนี โปรดดูที่เอกสารที่นี่

ตัวอย่าง:

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

หวังว่านี่จะช่วยได้!


34

ไม่มีฟังก์ชันในตัวเพื่อรับดัชนีการวนซ้ำ

ถ้าอย่างฉันคุณไม่ชอบความคิดที่จะสร้างMap(โครงสร้างข้อมูล) เพียงเพื่อดัชนีธรรมดาสิ่งที่คุณอาจต้องการคือmap(ฟังก์ชัน) ซึ่งให้ดัชนีแก่คุณ เรียกมันว่าmapIndexed(เหมือนใน Kotlin):

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

การใช้งานmapIndexedนั้นง่ายมาก:

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
นี่เป็นคำตอบที่ดี แต่น่าจะเขียนได้ดีกว่าในฐานะเครื่องกำเนิดไฟฟ้าแบบซิงโครนัส
David Rees

2
@DavidRees ขอบคุณสำหรับคำแนะนำ! ฉันเปลี่ยนชื่อฟังก์ชันด้วยmapIndexed
Vivien

เป็นเรื่องน่าเสียดายที่โผไม่มีวิธีง่ายๆในตัวในการทำเช่นนี้ งูเหลือมอายุ 30 ปีก็ทำได้ง่ายๆ!
osamu

ปรากฎว่า.asMap().forEach()โดยพื้นฐานแล้วจะเหมือนกับสิ่งนี้ - ดูคำตอบของฉัน
Timmmm

1
@Timmmm ฉันคิดว่าasMap()จะต้องเสียค่าใช้จ่ายเพิ่มเติมในการดึงข้อมูลดังนั้นจึงไม่มีประสิทธิภาพดังที่mapIndexed()กล่าวมา
anticafe

17

สร้างบนคำตอบ @Hemanth Raj

ในการแปลงกลับคุณสามารถทำได้

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

หรือถ้าคุณต้องการดัชนีสำหรับฟังก์ชันการทำแผนที่คุณสามารถทำได้:

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

14

เริ่มต้นด้วย Dart 2.7 คุณสามารถใช้extensionเพื่อขยายฟังก์ชัน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++));
  }
}

การใช้งาน:

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
นี่คือคำตอบที่ดีที่สุดสิ่งนี้ยังใช้ได้กับรายการ Flutter ที่คุณสามารถส่งคืนวิดเจ็ตไม่ใช่แค่สตริง
STEEL

7

แพ็คเกจเพิ่มเติมของ Lukas Renggli มีเครื่องมือที่มีประโยชน์มากมายรวมถึง 'จัดทำดัชนี' ซึ่งทำในสิ่งที่คุณต้องการ จากเอกสาร:

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

(คุณสามารถเพิกเฉยต่ออาร์กิวเมนต์ชดเชยเว้นแต่คุณจะมีพื้นหลัง Smalltalk :-)


7

ตอนแรกฉันคิดว่า['one', 'two', 'three'].asMap().forEach((index, value) { ... });จะไม่มีประสิทธิภาพจริงๆเพราะดูเหมือนว่าจะแปลงรายการเป็นแผนที่ จริงๆแล้วไม่ใช่ - เอกสารระบุว่าสร้างมุมมองที่ไม่เปลี่ยนรูปของรายการ ฉันตรวจสอบอีกครั้งด้วยdart2jsรหัสนี้:

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

มันสร้างจำนวนมากของรหัส! แต่สาระสำคัญคือ:

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

ดังนั้นจึงฉลาดพอที่จะทำสิ่งที่มีประสิทธิภาพ! ฉลาดทีเดียว

แน่นอนคุณสามารถใช้ปกติสำหรับการวนซ้ำ:

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

4

เพื่อความสะดวกคุณสามารถใช้วิธีการขยายนี้

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

ใช้asMapเพื่อแปลงรายการเป็นแผนที่ก่อน ดัชนีขององค์ประกอบคือกุญแจสำคัญ องค์ประกอบกลายเป็นมูลค่า ใช้รายการเพื่อแมปคีย์และค่ากับสิ่งที่คุณต้องการ

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

เอาท์พุต:

[0:a, 1:b, 2:c]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.