通过索引和DART中的列表枚举或映射



在飞镖中,有任何等效的:

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

有一个asMap方法将List转换为Map,其中键为索引,值为元素。请查看ASMAP的文档。

示例:

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

如果您使用的是DART 3,则可以使用indexed属性。请查看索引的文档。

示例:

final sample = ['a', 'b', 'c'];
for (final (index, item) in sample.indexed) {
  f(index, item);
}

您可以从collection软件包中使用mapIndexedforEachIndexed扩展方法。请注意,与JavaScript的array.map()或C#的IEnumerable.Select()不同,索引是第一个参数,而不是回调的第二个参数:

import 'package:collection/collection.dart';
void main() {
  final inputs = ['a', 'b', 'c', 'd', 'e', 'f'];
  final indexes = inputs.mapIndexed((index, element) => index).toList();
  
  inputs.forEachIndexed((index, element) {
    print('index: $index, element: $element');
  });
  print(indexes);
}

实时演示


旧答案

从DART 2.7开始,您可以使用extension方法扩展Iterable的功能,而不必编写助手功能:

extension ExtendedIterable<E> on Iterable<E> {
  /// Like Iterable<T>.map but the callback has index as second argument
  Iterable<T> mapIndexed<T>(T Function(E e, int i) f) {
    var i = 0;
    return map((e) => f(e, i++));
  }
  void forEachIndexed(void Function(E e, int i) f) {
    var i = 0;
    forEach((e) => f(e, i++));
  }
}

用法:

final inputs = ['a', 'b', 'c', 'd', 'e', 'f'];
final results = inputs
  .mapIndexed((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.forEachIndexed((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

实时演示

没有内置功能来获取迭代索引。

如果像我一样,您不喜欢为简单索引构建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;
  }
}

在@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']

我最初认为['one', 'two', 'three'].asMap().forEach((index, value) { ... });确实效率低下,因为它看起来像是将列表转换为地图。实际上不是 - 文档说它创建了列表的不变视图。我与此代码的dart2js进行了仔细检查:

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

它生成代码的 lot !但是要点是:

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

使用 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]

使用 - &gt;mapIndexed(索引,元素)函数

将每个元素及其索引映射到一个新值。

import 'package:collection/collection.dart';

并使用地图索引如下

(List).mapIndexed<Widget>(
 (mapIndex, mapElement) => Positioned(
  left: mapIndex.toDouble() * 5,
  child: Card(
   color: Colors.blue,
    child: Image.network(
     '${mapElement.ImageURL}',
      height: 80,
      width: 80))))

请参考:https://pub.dev/documentation/collection/latest/collection/collection/iterableextension/mapindexed.html

lukas renggli的更多软件包包含许多有用的工具,包括'索引',这些工具正是您想要的。从文档中:

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

(除非您有SmallTalk背景: - )。

,您可以忽略偏移参数

您可以从集合软件包中使用mapIndexed扩展名:

import 'package:collection/collection.dart';
void main() {
  final nums = [1, 2, 3];
  final strs = nums.mapIndexed((index, element) => index.toString() + '_' + element.toString()).toList();
  print(strs); //  [0_1, 1_2, 2_3]
}

为方便起见,您可以使用此扩展方法。

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

您可以使用Iterable.generate工厂。以下代码将使用索引和值映射Iterable

extension IterableMapIndex<T> on Iterable<T> {
  Iterable<E> mapIndexed<E>(E f(int index, T t)) {
    return Iterable.generate(this.length, (index)=>f(index, elementAt(index)));
  }
}

使用Dart Collection软件包您可以访问各种列表扩展

一个是mapIndexed

Iterable<R> mapIndexed<R>(R Function(int, E) convert)

列表的所有迭代扩展名

带有DART 3中的记录,将新的扩展属性索引添加到IterableExtensions中,可以像这样使用:

final iterable = [1,2,3,4];
for(var (index, value) in iterable.indexed) {
    print('$index => $value)
}

package:quiver包含一个类似于Python的enumerate函数的enumerate功能。

(请注意,尽管package:quiver不是DART团队,但它由Google拥有和维护,其许多贡献者是Google的Dart和Flutter团队的成员。)

这是2023年的解决方案,该解决方案使用了新的飞镖3记录类型。

您可以这样使用:

for (final (index, item) in enumerate(items)) {
  print('$index: $item');
}

这是辅助功能:

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

它类似于Python中的enumerate函数。

您可以创建另一个变量以获取索引。

    int index = 0;
    array?.forEach((element) {
    
    // your code is here
    index++; // you should add this at end of the for loop
    });

最新更新