Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add list move extensions #165

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions lib/src/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,150 @@ extension ListFlattenExtension<E> on List<List<E>> {
/// ```
List<E> flatten() => [for (final list in this) ...list];
}

extension ListMoveExtension<E> on List<E> {
/// Moves the [element] from its current index to the [newIndex].
///
/// ```dart
/// final list = [1, 2, 3];
/// list.move(1, 2); // [2, 3, 1]
/// ```
void move(E element, int newIndex) {
RangeError.checkValidIndex(newIndex, this, 'newIndex');

final currentIndex = indexOf(element);

if (currentIndex < 0) {
return;
}

removeAt(currentIndex);
insert(newIndex, element);
}
}

extension ListMoveAtExtension<E> on List<E> {
/// Moves the element at the [oldIndex] to the [newIndex].
///
/// ```dart
/// final list = [1, 2, 3];
/// list.moveAt(0, 2); // [2, 3, 1]
/// ```
void moveAt(int oldIndex, int newIndex) {
RangeError.checkValidIndex(oldIndex, this, 'oldIndex');
RangeError.checkValidIndex(newIndex, this, 'newIndex');

final element = this[oldIndex];

removeAt(oldIndex);
insert(newIndex, element);
}
}

extension ListMoveAllExtension<E> on List<E> {
/// Moves all the elements that satisfy the given [predicate] to the [newIndex].
///
/// ```dart
/// final list = [1, 2, 3];
/// list.moveAll(1, (element) => element.isOdd); // [2, 1, 3]
/// ```
void moveAll(int newIndex, bool Function(E element) predicate) {
RangeError.checkValidIndex(newIndex, this, 'newIndex');

final split = partition(predicate);

clear();
addAll(split[1]);
insertAll(newIndex, split[0]);
}
}

extension ListMoveUpExtension<E> on List<E> {
/// Moves the [element] up by one index increment unless it is at the top already.
///
/// Returns `true` if the move was successful otherwise `false`.
///
/// ```dart
/// final list = [1, 2, 3];
/// list.moveUp(3); // [1, 3, 2]
/// ```
bool moveUp(E element) {
final currentIndex = indexOf(element);

if (currentIndex > 0) {
removeAt(currentIndex);
insert(currentIndex - 1, element);
return true;
} else {
return false;
}
}
}

extension ListMoveUpAtExtension<E> on List<E> {
/// Moves the element at the [index] up by one index increment unless it is at the top already.
///
/// Returns `true` if the move was successful otherwise `false`.
///
/// ```dart
/// final list = [1, 2, 3];
/// list.moveUpAt(2); // [1, 3, 2]
/// ```
bool moveUpAt(int index) {
RangeError.checkValidIndex(index, this, 'index');

if (index > 0) {
final element = this[index];
removeAt(index);
insert(index - 1, element);
return true;
} else {
return false;
}
}
}

extension ListMoveDownExtension<E> on List<E> {
/// Moves the [element] down by one index increment unless it is at the bottom already.
///
/// Returns `true` if the move was successful otherwise `false`.
///
/// ```dart
/// final list = [1, 2, 3];
/// list.moveDown(1); // [2, 1, 3]
/// ```
bool moveDown(E element) {
final currentIndex = indexOf(element);

if (currentIndex >= 0 && currentIndex < length - 1) {
removeAt(currentIndex);
insert(currentIndex + 1, element);
return true;
} else {
return false;
}
}
}

extension ListMoveDownAtExtension<E> on List<E> {
/// Moves the element at the [index] down by one index increment unless it is at the bottom already.
///
/// Returns `true` if the move was successful otherwise `false`.
///
/// ```dart
/// final list = [1, 2, 3];
/// list.moveDownAt(0); // [2, 1, 3]
/// ```
bool moveDownAt(int index) {
RangeError.checkValidIndex(index, this, 'index');

if (index >= 0 && index < length - 1) {
final element = this[index];
removeAt(index);
insert(index + 1, element);
return true;
} else {
return false;
}
}
}
79 changes: 79 additions & 0 deletions test/list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,84 @@ void main() {
final List<int> flatten = nestedList.flatten();
expect(flatten, [0, 0, 0, 1, 1, 1, 2, 2, 2]);
});

test('.move()', () {
final list = [1, 2, 3];
expect(list..move(1, 0), [1, 2, 3]);
expect(list..move(1, 2), [2, 3, 1]);
expect(list..move(3, 0), [3, 2, 1]);
expect(() => list..move(3, 3), throwsA(isA<RangeError>()));
});

test('.moveAt()', () {
final list = [1, 2, 3];
expect(list..moveAt(0, 0), [1, 2, 3]);
expect(list..moveAt(0, 2), [2, 3, 1]);
expect(list..moveAt(1, 0), [3, 2, 1]);
expect(() => list..moveAt(3, 0), throwsA(isA<RangeError>()));
expect(() => list..moveAt(0, 3), throwsA(isA<RangeError>()));
});

test('.moveAll()', () {
final list = [1, 2, 3];
expect(
list..moveAll(1, (element) => element < 3),
[3, 1, 2],
);
expect(
list..moveAll(1, (element) => element == 2),
[3, 2, 1],
);
expect(
() => list..moveAll(3, (element) => true),
throwsA(isA<RangeError>()),
);
});

test('.moveUp()', () {
final list = [1, 2, 3];
expect(list.moveUp(0), isFalse);
expect(list, [1, 2, 3]);
expect(list.moveUp(1), isFalse);
expect(list, [1, 2, 3]);
expect(list.moveUp(2), isTrue);
expect(list, [2, 1, 3]);
expect(list.moveUp(3), isTrue);
expect(list, [2, 3, 1]);
});

test('.moveUpAt()', () {
final list = [1, 2, 3];
expect(list.moveUpAt(0), isFalse);
expect(list, [1, 2, 3]);
expect(list.moveUpAt(1), isTrue);
expect(list, [2, 1, 3]);
expect(list.moveUpAt(2), isTrue);
expect(list, [2, 3, 1]);
expect(() => list.moveUpAt(3), throwsA(isA<RangeError>()));
});

test('.moveDown()', () {
final list = [1, 2, 3];
expect(list.moveDown(0), isFalse);
expect(list, [1, 2, 3]);
expect(list.moveDown(3), isFalse);
expect(list, [1, 2, 3]);
expect(list.moveDown(2), isTrue);
expect(list, [1, 3, 2]);
expect(list.moveDown(1), isTrue);
expect(list, [3, 1, 2]);
});

test('.moveDownAt()', () {
final list = [1, 2, 3];
expect(list.moveDownAt(2), isFalse);
expect(list, [1, 2, 3]);
expect(list.moveDownAt(1), isTrue);
expect(list, [1, 3, 2]);
expect(list.moveDownAt(0), isTrue);
expect(list, [3, 1, 2]);
expect(() => list.moveDownAt(3), throwsA(isA<RangeError>()));
});
});
}