code

0부터 N까지의 목록 만들기

starcafe 2023. 5. 8. 22:21
반응형

0부터 N까지의 목록 만들기

다트에서 연속 정수 범위를 쉽게 만들 수 있는 방법은 무엇입니까?예:

// throws a syntax error :)
var list = [1..10];

List.generate 생성자를 사용할 수 있습니다.

var list = new List<int>.generate(10, (i) => i + 1);

또는 제너레이터를 사용할 수 있습니다.

/// the list of positive integers starting from 0
Iterable<int> get positiveIntegers sync* {
  int i = 0;
  while (true) yield i++;
}
void main() {
  var list = positiveIntegers
      .skip(1)   // don't use 0
      .take(10)  // take 10 numbers
      .toList(); // create a list
  print(list);   // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}

Dart 2.3 이후에는 수집을 다음에 사용할 수 있습니다.

var list = [for (var i = 1; i <= 10; i++) i];

수집 기능이 있는 Dart 2.3.0 이후:

var list = [for(var i=0; i<10; i+=1) i];

Dart의 Iterable.generate 함수를 사용하여 0..n-1 사이의 범위를 만들 수도 있습니다.

var list = Iterable<int>.generate(10).toList()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

@가니메데:

다음은 간단한 a.to(b) 솔루션입니다.

extension RangeExtension on int {
  List<int> upTo(int maxInclusive) =>
    [for (int i = this; i <= maxInclusive; i++) i];
}

또는 선택적 단계 크기:


extension RangeExtension on int {
  List<int> upTo(int maxInclusive, {int stepSize = 1}) =>
      [for (int i = this; i <= maxInclusive; i += stepSize) i];
}

마지막 것을 다음과 같이 사용합니다.

void main() {
  // [5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50]
  print(5.upTo(50, stepSize: 3));
}

제가 알기로는 다트에서 이와 동등한 원주민 방법은 없습니다.하지만 당신은 당신만의 것을 만들 수 있습니다.Rangeclass, 또는 의존성이 괜찮다면 https://pub.dartlang.org/packages/range 을 사용합니다.

Olov Lassus는 얼마 전에 자신의 Range 클래스를 구현하는 것에 대한 기사를 썼습니다.

편집: 내가 방금 생각한 훨씬 더 좋은 방법:

Iterable<int> range(int low, int high) sync* {
  for (int i = low; i < high; ++i) {
    yield i;
  }
}

void main() {
  for(final i in range(1, 20)) {
    print(i);
  }
}

Quiver 패키지에는 많은 Python과 유사한 반복기가 정의되어 있습니다.

예를 들어, 다음을 사용합니다.range()함수:

import 'package:quiver/iterables.dart';

print(range(10).toList().toString());

출력:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

에서도 잘 작동합니다.for루프:

for (var i in range(1, 11))
  print('$i');

다른 많은 유용한 반복기도 제공됩니다.

나는 파이썬에서 제공하는 범위()를 모방하려고 시도하는 알렉상드르 아르두인의 수정된 버전을 사용해 왔습니다. 편집: 선택적 위치 인수는 아래 업데이트된 코드임을 발견했습니다.

range(int stop, {int start: 0, int step: 1}){
  if (step == 0)
    throw Exception("Step cannot be 0");

  return start < stop == step > 0
  ? List<int>.generate(((start-stop)/step).abs().ceil(), (int i) => start + (i * step))
  : [];
}

사용 예:

range(16, start:-5, step: 8);
// [-5, 3, 11]
range(5);
// [0, 1, 2, 3, 4]

안타깝게도 다트에는 연산자 오버로드나 선택적 위치 인수가 없기 때문에 더 쉬운 파이썬 구문(범위(시작, 중지[, 단계])을 완전히 모방하지 못했습니다.

메리안의 솔루션과 유사한 목록 이해를 사용하는 다른 옵션

listCompRange(int start, int stop, int step) {
  if (step == 0)
    throw Exception("Step cannot be 0");
  if (start == stop)
    return [];
  bool forwards = start < stop;
  return forwards == step > 0
  ? forwards 
    ? [for (int i = 0; i*step < stop-start; i++) start + (i * step)]
    : [for (int i = 0; i*step > stop-start; i++) start + (i * step)]
  : [];
}

사용 예:

listCompRange(0, 5, 1);
// [0, 1, 2, 3, 4]

다음 방법으로 이 두 가지 옵션을 모두 벤치마킹했습니다.

benchMarkRange(){
  List<List<int>> temp = List<List<int>>();
  Stopwatch timer = Stopwatch();
  timer.start();
  for (int i = 0; i < 500; i++){
    temp.add(range(-30, start: -10, step: -2));
  }
  timer.stop();
  print("Range function\n${timer.elapsed}\n");
  return temp;
}

benchMarkListComprehension(){
  List<List<int>> temp = List<List<int>>();
  Stopwatch timer = Stopwatch();
  timer.start();
  for (int i = 0; i < 500; i++){
    temp.add(listCompRange(-10, -30, -2));
  }
  timer.stop();
  print("List comprehension\n${timer.elapsed}\n");
  return temp;
}

이러한 결과를 생성기에 약간 유리하게 만들었습니다.

Range function
0:00:00.011953
0:00:00.011558
0:00:00.011473
0:00:00.011615

List comprehension
0:00:00.016281
0:00:00.017403
0:00:00.017496
0:00:00.016878

그러나 함수를 -10에서 -30으로 변경하여 -2의 단계로 생성했을 때 결과는 목록 이해에 약간 호의적이었습니다.

List comprehension
0:00:00.001352             
0:00:00.001328                
0:00:00.001300
0:00:00.001335

Range function
0:00:00.001371
0:00:00.001466
0:00:00.001438
0:00:00.001372

명명된 매개 변수가 아닌 위치 매개 변수를 사용하여 코드

range(int a, [int stop, int step]) {
  int start;

  if (stop == null) {
    start = 0;
    stop = a;
  } else {
    start = a;
  }  

  if (step == 0)
    throw Exception("Step cannot be 0");

  if (step == null)
    start < stop 
    ? step = 1    // walk forwards
    : step = -1;  // walk backwards

  // return [] if step is in wrong direction
  return start < stop == step > 0
  ? List<int>.generate(((start-stop)/step).abs().ceil(), (int i) => start + (i * step))
  : [];
}

용도: 범위(inta, [int stop, int step])

Stop이 포함되지 않은 경우 Stop 및 Start가 기본값으로 0이 됩니다. a와 stop이 모두 제공된 경우 a가 기본값으로 제공되지 않은 경우 start가 기본값으로 1 또는 -1로 설정됩니다. 또는 stop이 더 큰지 여부에 따라 1 또는 -1이 됩니다.

range(4);
// [0, 1, 2, 3]
range(4, 10);
// [4, 5, 6, 7, 8, 9]
range(4, 10, 2);
// [4, 6, 8]
range(-4);
// [0, -1, -2, -3]
range(10, 4);
// [10, 9, 8, 7, 6, 5]
range(10,10);
// []
range(1, 2, -1);
// []
range(x, y, 0);
// Exception
void main() {
  print(List.generate(10, (index) => index));
}


[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

List.generate새 목록을 반환합니다.

내 것은 N을 만드는 가장 우아한 해결책이 아닐 수도 있습니다.M 목록이지만 다음을 구현할 수 있을 정도로 유용하고 간단했습니다.

void main() {
  generateN2MList(2, 8);
  generateN2MList(4, 10);
  generateN2MList(1, 3);
  generateN2MList(0, 13, true);
}

void generateN2MList(int n, int m, [bool excludeLimits = false]) {
  final diff = m - n;
  final times = excludeLimits ? diff - 1 : diff + 1;
  final startingIdx = excludeLimits ? n + 1 : n;
  List<int> generated =
      List.generate(times, (i) => startingIdx + i);

  print(generated);
}

테스트해 보면 다음과 같은 결과가 나옵니다.

[2, 3, 4, 5, 6, 7, 8]
[4, 5, 6, 7, 8, 9, 10]
[1, 2, 3]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

여기 다트패드가 있습니다. 가지고 놀고 싶다면 말이죠.

진정한 범위를 생성한 다음 서로 다른 범위를 비교하려면 range_type을 고려할 수 있습니다.

  final july = DateTimeRange.parse('[2022-07-01, 2022-08-01)');
  final scheduleDate1 = DateTime(2022, 07, 02);
  final scheduleDate2 = DateTime(2022, 08, 07);
  final workingDays = DateTimeRange.parse('[2022-07-20, 2022-08-15)');
  print('Is scheduleDate1 in July? ${july.containsElement(scheduleDate1)}');
  print('Is scheduleDate2 in July? ${july.containsElement(scheduleDate2)}');
  print('Is workingDays overlaps? ${july.overlap(workingDays)}');
  print('workingDays intersection: ${july.intersection(workingDays)}');
  print('workingDays union: ${july.union(workingDays)}');
  print('july difference workingDays: ${july.difference(workingDays)}');

위의 방법들은 정말 느립니다.List목록을 구성하기 와 시간을 , 기반접방근실식전구목때록성체반기면추문는소시하비메간모을와리가에하을은제로▁consumes,▁and▁a▁-▁memory▁it▁because,반▁approach,yield) 반방예배은법들어다기음다다측 2정니됩으로보를▁▁than다측▁slowerx니▁to배▁(▁measuredfor▁be정됩▁method예based▁2▁example))보다 2배 느린 것으로 측정됩니다.for(var i=0;i<N;++i)

https://github.com/dart-lang/sdk/issues/50280#issuecomment-1288679644, 에서 @lrhn은 다음을 제공합니다.range만큼 .for(var i=0;i<N;++i) 드코:

class Range extends Iterable<int> {
  final int start, end, step;

  @pragma('dart2js:tryInline')
  @pragma('vm:prefer-inline')
  Range(this.start, this.end, [this.step = 1]);

  @pragma('dart2js:tryInline')
  @pragma('vm:prefer-inline')
  @override
  Iterator<int> get iterator => RangeIterator(start, end, step);
}

class RangeIterator implements Iterator<int> {
  int _current;
  final int _end, _step;

  @pragma('dart2js:tryInline')
  @pragma('vm:prefer-inline')
  RangeIterator(int start, this._end, this._step) : _current = start - _step;

  @override
  @pragma('dart2js:tryInline')
  @pragma('vm:prefer-inline')
  bool moveNext() {
    _current += _step;
    return _current < _end;
  }

  @override
  @pragma('dart2js:tryInline')
  @pragma('vm:prefer-inline')
  int get current => _current;
}

@pragma('dart2js:tryInline')
@pragma('vm:prefer-inline')
Iterable<int> range(int startOrLength, [int? end, int step = 1]) {
  assert(step > 0);
  int start = startOrLength;
  if (end == null) {
    end = start; // ignore: parameter_assignments
    start = 0;
  }
  return Range(start, end, step);
}

void main() {
  test('range', () {
    expect(range(3), [0, 1, 2]);
    expect(range(1, 4), [1, 2, 3]);
    expect(range(-2, 2), [-2, -1, 0, 1]);

    expect(range(0), <int>[]);
    expect(range(5, 5), <int>[]);
    expect(range(-1), <int>[]);
    expect(range(5, 4), <int>[]);
  });
}

다을사용음생성수를 사용하여 음수 List<int>.generate방법

void main(List<String> args){
  int start = -10, end = 3; // generating numbers from [-10, 3)
  var list = List<int>.generate(end - start, (i) => start + i);
  print(list);
}

출력:

[-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2]

언급URL : https://stackoverflow.com/questions/37798397/create-a-list-from-0-to-n

반응형