Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - Check if an index exists in List

Tags:

flutter

dart

Let's say I have a list:

List<int> numbers = [1, 2, 3, 4, 5,];

How can I check if object in the list exists at certain index??

E.g.

if (numbers[6] != null) {
  print('Exists');
}

I was hoping I can do smth like that, but apparently it's not working.

like image 988
Shalugin Avatar asked Jan 16 '20 04:01

Shalugin


People also ask

How do you find the index of an element in a list Dart?

The method indexOf() returns the index of the first occurrence of the element in the list if found. Otherwise, it returns -1.

How do you check if an object is in a list in flutter?

How do you check if an object is in a list in flutter? Using List. contains( ) is the recommended method to check if a value is present in a list or not. This method takes the value to be searched as a parameter and returns true if the item found otherwise returns false.

How do I use indexWhere in flutter?

indexWhere method Null safety The first index in the list that satisfies the provided test . Searches the list from index start to the end of the list. The first time an object o is encountered so that test(o) is true, the index of o is returned. Returns -1 if element is not found.

How do you get items in Dart list?

Dart – Get Element at Specific Index To get an element at specific index from a List in Dart, call elementAt() method on this list and pass the index as argument. elementAt() method returns the element. If the index is out of range for the list, then elementAt() throws RangeError .


2 Answers

You can convert the List to a Map and check the keys:

List<int> numbers = [1, 2, 3, 4, 5,];

//Check if index 7 is valid
if (numbers.asMap().containsKey(7)) {
  print('Exists');
} else {
  print('Doesn\'t exist');
}

//[EDIT] Check if item at index 4 exists and is 5
if (numbers.asMap()[4] == 5) {
  print("Index 4 = 5");
} else {
  print("Index 4 != 5");
}
like image 137
Carlos Javier Córdova Reyes Avatar answered Sep 21 '22 20:09

Carlos Javier Córdova Reyes


I'm confused by the other provided answers. Judging from the question text, all these helper functions and conversions of the list to maps and such is extreme overkill. What's wrong with a simple if check?

var list = [1, 2, 3, 4, 5];
var index = 4;
var value = 5;

if (list.length > index && list[index] == value) {
  ...
}

Elegance is in simplicity, not in a certain code format. Converting the list to a map takes work and you duplicate your data, all for literally no reason. Code readability may often be more important than performance these days, but that's no reason to use a knowingly terrible practice for such a minimal cosmetic gain.

And even if the above approach really bugs you so much, you can always just wrap it in an extension method:

extension ListExtensions<T> on List<T> {
  bool containsAt(T value, int index) {
    assert(this != null);
    return index >= 0 && this.length > index && this[index] == value;
  }
}

// Usage

var list = [1, 2, 3, 4, 5];
var index = 4;
var value = 5;

if(list.containsAt(value, index)) {
  ...
}

EDIT: The array.indices field in Swift is a Range, and calling contains checks if a value is within that range. Because of the way Range works, checking if a value is within it is a constant-time operation, which is why it's so efficient. In fact, the following approaches in Swift perform more or less identically:

let array = [1, 2, 3, 4, 5]
let idx = 2

// array.indices approach
if array.indices.contains(idx) {
  ...
}

// Manual check approach
if idx >= 0 && idx < array.count {
  ...
}

Flutter doesn't have the Range type, so trying to perform code acrobatics to get the equivalent-looking code results in a horribly inefficient way to simply check if an index exists in a list. For example, here's the comparison between the list.asMap().contains(idx) approach in the selected answer and it's plain-code equivalent:

var list = [1, 2, 3, 4, 5];
var idx = 2;

// asMap approach
if (list.asMap().containsKey(idx)) {
  ...
}

// Manual conversion and check approach
Map<int, int> map = {};
for (var i = 0; i < list.length; i++) {
  map[i] = list[i];
} 
if (map.containsKey(idx)) {
  ...
}

As you can see, converting the list to a Map is a linear process, not a constant one, so if the list is a long one this could take quite a long time. Not just that, but you also end up creating a completely redundant Map object that contains all the elements of the list as well as the indices as its keys, so you've essentially doubled your memory footprint (or even tripled it considering maps store both key and value). Hopefully, you can see why this approach to checking if a list contains an index is worse in every regard to the "normal" way. (And in a comment he suggests calling asMap twice????)


The Range type in Swift isn't that hard to make in Dart, though, and with the extension method approach from above you could achieve identical syntax AND performance:

(range.dart)

class Range extends Iterable<int> {
  const Range(this.start, this.end) : assert(start <= end);
  const Range.fromLength(int length) : this(0, length - 1);

  final int start;
  final int end;

  int get length => end - start + 1;

  @override
  Iterator<int> get iterator => Iterable.generate(length, (i) => start + i).iterator;

  @override
  bool contains(Object? index) {
    if (index == null || index is! int) return false;
    return index >= start && index <= end;
  }

  @override
  String toString() => '[$start, $end]';
}

(list_extensions.dart)

import 'range.dart';

extension ListExtensions on List {
  Range get indices => Range.fromLength(this.length);
}

(main.dart)

import 'list_extensions.dart';

main() {
  final list = [1, 2, 3, 4, 5];
  print(list.indices);              // [0, 4]
  print(list.indices.contains(3));  // true
  print(list.indices.contains(5));  // false
  print(list.indices.contains(-1)); // false
}

Having said all of this, the second aspect of your question wouldn't be covered by this, and you'd still have to check the index itself for the value. (Note that you would have to do this in Swift, too)

if (list.indices.contains(index) && list[index] == value) {
  // `value` exists in the list at `index`
  ...
}
like image 36
Abion47 Avatar answered Sep 19 '22 20:09

Abion47