Skip to content

Commit

Permalink
Merge branch 'master' into feature/remove_first_or_null
Browse files Browse the repository at this point in the history
  • Loading branch information
passsy authored Oct 31, 2021
2 parents f8d2b14 + b29dc21 commit 35337cd
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 6 deletions.
1 change: 1 addition & 0 deletions lib/kt.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ library kotlin_dart;
export "package:kt_dart/annotation.dart";
export "package:kt_dart/collection.dart";
export "package:kt_dart/exception.dart";
export 'package:kt_dart/src/string/string.dart';
export "package:kt_dart/standard.dart";
11 changes: 11 additions & 0 deletions lib/src/collection/kt_collection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ extension KtCollectionExtensions<T> on KtCollection<T> {
return elementAt(r.nextInt(size));
}

/// Returns a random element from this collection.
///
/// returns null if this collection is empty.
T? randomOrNull([math.Random? random]) {
if (!isNotEmpty()) return null;
final r = random ?? math.Random();
final index = r.nextInt(size);
if (index >= size) return null;
return elementAt(index);
}

/// Returns a [KtMutableList] filled with all elements of this collection.
KtMutableList<T> toMutableList() => KtMutableList<T>.from(iter);
}
Expand Down
80 changes: 76 additions & 4 deletions lib/src/collection/kt_iterable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ abstract class KtIterable<T> {
extension KtComparableIterableExtension<T extends Comparable<T>>
on KtIterable<T> {
/// Returns the largest element or `null` if there are no elements.
T? max() {
@Deprecated("use maxOrNull")
T? max() => maxOrNull();

/// Returns the largest element or `null` if there are no elements.
T? maxOrNull() {
final i = iterator();
if (!iterator().hasNext()) return null;
T max = i.next();
Expand All @@ -31,7 +35,11 @@ extension KtComparableIterableExtension<T extends Comparable<T>>
}

/// Returns the smallest element or `null` if there are no elements.
T? min() {
@Deprecated("use minOrNull")
T? min() => minOrNull();

/// Returns the smallest element or `null` if there are no elements.
T? minOrNull() {
final i = iterator();
if (!iterator().hasNext()) return null;
T min = i.next();
Expand All @@ -47,7 +55,11 @@ extension KtComparableIterableExtension<T extends Comparable<T>>

extension KtNumIterableExtension<T extends num> on KtIterable<T> {
/// Returns the largest element or `null` if there are no elements.
T? max() {
@Deprecated("use maxOrNull")
T? max() => maxOrNull();

/// Returns the largest element or `null` if there are no elements.
T? maxOrNull() {
final i = iterator();
if (!iterator().hasNext()) return null;
T max = i.next();
Expand All @@ -63,7 +75,11 @@ extension KtNumIterableExtension<T extends num> on KtIterable<T> {
}

/// Returns the smallest element or `null` if there are no elements.
T? min() {
@Deprecated("use minOrNull")
T? min() => minOrNull();

/// Returns the smallest element or `null` if there are no elements.
T? minOrNull() {
final i = iterator();
if (!iterator().hasNext()) return null;
T min = i.next();
Expand Down Expand Up @@ -613,6 +629,29 @@ extension KtIterableExtensions<T> on KtIterable<T> {
return list;
}

/// Returns a single list of all elements yielded from results of [transform]
/// function being invoked on each element and its index in the original
/// collection.
KtList<R> flatMapIndexed<R>(KtIterable<R> Function(int index, T) transform) {
final list = flatMapIndexedTo(mutableListOf<R>(), transform);
// making a temp variable here, it helps dart to get types right ¯\_(ツ)_/¯
// TODO ping dort-lang/sdk team to check that bug
return list;
}

/// Appends all elements yielded from results of [transform] function being
/// invoked on each element and its index in the original collection, to the
/// given [destination].
C flatMapIndexedTo<R, C extends KtMutableCollection<R>>(
C destination, KtIterable<R> Function(int index, T) transform) {
var index = 0;
for (final element in iter) {
final list = transform(index++, element);
destination.addAll(list);
}
return destination;
}

/// Appends all elements yielded from results of [transform] function being invoked on each element of original collection, to the given [destination].
C flatMapTo<R, C extends KtMutableCollection<R>>(
C destination, KtIterable<R> Function(T) transform) {
Expand Down Expand Up @@ -1168,6 +1207,39 @@ extension KtIterableExtensions<T> on KtIterable<T> {
return accumulator;
}

/// Returns a list containing successive accumulation values generated by applying [operation] from left to right to each element and current accumulator value that starts with the first element of this collection.
KtList<S> runningReduce<S>(S Function(S acc, T) operation) {
final i = iterator();
if (!i.hasNext()) {
return emptyList();
}
S accumulator = i.next() as S;
final result = mutableListOf<S>()..add(accumulator);
while (i.hasNext()) {
accumulator = operation(accumulator, i.next());
result.add(accumulator);
}
return result;
}

/// Returns a list containing successive accumulation values generated by applying [operation] from left to right
/// to each element, its index in the original collection and current accumulator value that starts with the first
/// element of this collection.
KtList<S> runningReduceIndexed<S>(S Function(int index, S acc, T) operation) {
final i = iterator();
if (!i.hasNext()) {
return emptyList();
}
S accumulator = i.next() as S;
final result = mutableListOf<S>()..add(accumulator);
int index = 1;
while (i.hasNext()) {
accumulator = operation(index++, accumulator, i.next());
result.add(accumulator);
}
return result;
}

/// Returns a list with elements in reversed order.
KtList<T> reversed() {
if (this is KtCollection && (this as KtCollection).size <= 1) {
Expand Down
16 changes: 16 additions & 0 deletions lib/src/string/string.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:meta/meta.dart';

extension StringReplaceFirstCharExtension on String {
/// Returns a copy of this string having its first character replaced with the result of the specified transform,
/// or the original string if it's empty.
/// transform - function that takes the first character and returns the result of the transform applied to the character.
@pragma('vm:prefer-inline')
@pragma('dart2js:tryInline')
@experimental
String replaceFirstChar(String Function(String) transform) {
if (isNotEmpty) {
return transform(this[0]).toString() + substring(1);
}
return this;
}
}
33 changes: 33 additions & 0 deletions test/collection/collection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,39 @@ void testCollection(KtCollection<T> Function<T>() emptyCollection,
});
});

group("randomOrNull", () {
test("random item or null with random parameter", () {
final collection = collectionOf(["a", "b", "c"]);

final firstPick = collection.randomOrNull(NotRandom()..next = 2);
final pos2 = collection.elementAt(2);
if (ordered) expect(pos2, "c");

expect(firstPick, pos2);

final pos0 = collection.elementAt(0);
if (ordered) expect(pos0, "a");

final secondPick = collection.randomOrNull(NotRandom()..next = 0);
expect(secondPick, pos0);

final outOfRangePick = collection.randomOrNull(NotRandom()..next = 3);
expect(outOfRangePick, null);

final emptyCollection = collectionOf([]);
final pick1 = emptyCollection.randomOrNull(NotRandom()..next = 0);
expect(pick1, null);
});

test("randomOrNull works without passing a Random", () {
final collection = collectionOf(["a", "b", "c"]);
expect(collection.randomOrNull(),
anyOf(equals("a"), equals("b"), equals("c"), equals(null)));

final emptyCollection = collectionOf([]);
expect(emptyCollection.randomOrNull(), equals(null));
});
});
group("toString", () {
if (ordered) {
test("default string representation", () {
Expand Down
108 changes: 108 additions & 0 deletions test/collection/iterable_extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,32 @@ void testIterable(KtIterable<T> Function<T>() emptyIterable,
});
});

group("flatMapTo", () {
test("flatMapTo int to string", () {
final result = mutableListOf<int>();
final iterable = iterableOf([1, 2, 3]);
iterable.flatMapTo(result, (it) => iterableOf([it, it + 1, it + 2]));
expect(result, listOf(1, 2, 3, 2, 3, 4, 3, 4, 5));
});
});

group("flatMapIndexed", () {
test("flatMapIndexed int to string", () {
final iterable = iterableOf([1, 2, 3]);
expect(iterable.flatMapIndexed((ix, it) => iterableOf([ix, it])).toList(),
listOf(0, 1, 1, 2, 2, 3));
});
});

group("flatMapIndexedTo", () {
test("flatMapIndexedTo int to string", () {
final result = mutableListOf<int>();
final iterable = iterableOf([1, 2, 3]);
iterable.flatMapIndexedTo(result, (ix, it) => iterableOf([ix, it]));
expect(result, listOf(0, 1, 1, 2, 2, 3));
});
});

group("flatten", () {
test("empty", () {
final KtIterable<KtIterable<int>> nested =
Expand Down Expand Up @@ -1354,6 +1380,32 @@ void testIterable(KtIterable<T> Function<T>() emptyIterable,
});
});

group("maxOrNull", () {
test("gets max value int", () {
final iterable = iterableOf([1, 3, 2]);
final int? max = iterable.maxOrNull();
expect(max, 3);
});

test("gets max value double", () {
final iterable = iterableOf([1.0, 3.2, 2.0]);
final double? max = iterable.maxOrNull();
expect(max, 3.2);
});

test("gets max value comparable", () {
final iterable = iterableOf(["a", "x", "b"]);
final String? max = iterable.maxOrNull();
expect(max, "x");
});

test("empty iterable return null", () {
final iterable = emptyIterable<int>();
final int? max = iterable.maxOrNull();
expect(max, null);
});
});

group("maxBy", () {
test("gets max value", () {
final iterable = iterableOf(["1", "3", "2"]);
Expand Down Expand Up @@ -1432,6 +1484,32 @@ void testIterable(KtIterable<T> Function<T>() emptyIterable,
});
});

group("minOrNull", () {
test("gets min int value", () {
final KtIterable<int> iterable = iterableOf([3, 1, 2]);
final int? min = iterable.minOrNull();
expect(min, 1);
});

test("gets min double value", () {
final KtIterable<double> iterable = iterableOf([3.2, 1.4, 2.2]);
final double? min = iterable.minOrNull();
expect(min, 1.4);
});

test("gets max value comparable", () {
final iterable = iterableOf(["x", "b", "a", "h"]);
final String? min = iterable.minOrNull();
expect(min, "a");
});

test("empty iterable return null", () {
final iterable = emptyIterable<int>();
final int? min = iterable.minOrNull();
expect(min, null);
});
});

group("minBy", () {
test("gets min value", () {
final iterable = iterableOf(["1", "3", "2"]);
Expand Down Expand Up @@ -1712,6 +1790,36 @@ void testIterable(KtIterable<T> Function<T>() emptyIterable,
});
});

group("runningReduce", () {
if (ordered) {
test("runningReduce", () {
final result = iterableOf<String>(["a", "b", "c", "d"])
.runningReduce((String acc, it) => acc + it);
expect(result, listOf("a", "ab", "abc", "abcd"));
});
}

test("return empty list when list is empty", () {
expect(emptyIterable<int>().runningReduce((_, __) => "S"), emptyList());
});
});

group("runningReduceIndexed", () {
if (ordered) {
test("runningReduceIndexed", () {
final result = iterableOf<String>(["a", "b", "c", "d"])
.runningReduceIndexed(
(int index, String acc, it) => '$acc$it$index');
expect(result, listOf("a", "ab1", "ab1c2", "ab1c2d3"));
});
}

test("return empty list when list is empty", () {
expect(emptyIterable<int>().runningReduceIndexed((_, __, ___) => "S"),
emptyList());
});
});

group("reversed", () {
test("mutliple", () {
final result = iterableOf([1, 2, 3, 4]).reversed();
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions test/kt_dart_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import "collection/set_mutable_test.dart" as set_mutable_test;
import "collection/set_test.dart" as set_test;
import "collection/tuples_test.dart" as tuples_test;
import "exception/exceptions_test.dart" as exceptions_test;
import "issues/all_issues.dart" as all_issues;
import "issues/all_issues_test.dart" as all_issues_test;
import "standard/standard_test.dart" as standard_test;
import "util/annotation_test.dart" as annotation_test;
import "util/hash_test.dart" as hash_test;
Expand Down Expand Up @@ -61,7 +61,7 @@ void main() {
set_test.main();
tuples_test.main();
exceptions_test.main();
all_issues.main();
all_issues_test.main();
standard_test.main();
annotation_test.main();
hash_test.main();
Expand Down
41 changes: 41 additions & 0 deletions test/string/string_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import "package:kt_dart/kt.dart";
import "package:test/test.dart";

void main() {
group("replaceFirstChar", () {
group("uppercase", () {
test("empty string", () {
const String phrase = "";
final result = phrase.replaceFirstChar((it) => it.toUpperCase());
expect(result, '');
});
test("length 1", () {
const String phrase = "a";
final result = phrase.replaceFirstChar((it) => it.toUpperCase());
expect(result, 'A');
});
test("length 2", () {
const String phrase = "ab";
final result = phrase.replaceFirstChar((it) => it.toUpperCase());
expect(result, 'Ab');
});
});
group("lowercase", () {
test("empty string", () {
const String phrase = "";
final result = phrase.replaceFirstChar((it) => it.toLowerCase());
expect(result, '');
});
test("length 1", () {
const String phrase = "A";
final result = phrase.replaceFirstChar((it) => it.toLowerCase());
expect(result, 'a');
});
test("length 2", () {
const String phrase = "AB";
final result = phrase.replaceFirstChar((it) => it.toLowerCase());
expect(result, 'aB');
});
});
});
}

0 comments on commit 35337cd

Please sign in to comment.