Dart에서 인덱스와 값이있는 목록을 열거하거나 매핑합니다.


94

다트에는 공통점에 해당하는 것이 있습니다.

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

지도가 아닌 목록을 통해 열거
David Rees

Map # forEachList? 무슨 말이야? 문서는 "지도의 각 키 / 값 쌍에 f를 적용합니다. f를 호출하면지도에서 키를 추가하거나 제거해서는 안됩니다."
pskink

나는 또한 당신이 의미 "열거 나 인덱스와 값 목록을지도"를 이해하지 않는
귄터 Zöchbauer에게

답변:


143

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
이것은 좋은 대답이지만 아마도 동기식 생성기로 작성하는 것이 더 나을 것입니다.
데이빗리스

2
@DavidRees 제안을위한 thx! 또한 함수 이름을 변경했습니다.mapIndexed
Vivien

다트에이 작업을 수행하는 쉬운 방법이 내장되어 있지 않다는 것은 부끄러운 일입니다. 30 년 된 비단뱀이라도 쉽게 할 수 있습니다!
오사무

그것은 밝혀졌다 .asMap().forEach() 본질적으로 이것과 동일 것이 -내 대답을보십시오.
Timmmm

1
@Timmmm asMap()데이터를 검색하는 데 추가 루프가 필요하므로 mapIndexed()위와 같이 효율적이지 않습니다 .
안티 카페

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
이것이 최선의 대답입니다. 이것은 String뿐만 아니라 위젯을 반환 할 수있는 Flutter 항목에서도 작동합니다.
STEEL

7

Lukas Renggli의 더 많은 패키지에는 원하는 것을 정확히 수행하는 '인덱싱'을 포함한 많은 유용한 도구가 포함되어 있습니다. 문서에서 :

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

(Smalltalk 배경이 없으면 offset 인수를 무시할 수 있습니다. :-).


6

처음에는 ['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 루프를 사용할 수도 있습니다.

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.