Skip to content

Commit 6bd6f72

Browse files
committed
Implement Sample
1 parent 63498a0 commit 6bd6f72

File tree

4 files changed

+72
-0
lines changed

4 files changed

+72
-0
lines changed

lib/sample.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
library turf_sample;
2+
3+
export 'package:geotypes/geotypes.dart';
4+
export 'src/sample.dart';

lib/src/sample.dart

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import 'dart:math';
2+
import 'package:turf/turf.dart';
3+
4+
/// Returns a new [FeatureCollection] containing [num] randomly-selected features
5+
/// from the input collection, **without replacement**.
6+
///
7+
/// Throws [ArgumentError] if:
8+
/// * [fc] is `null`
9+
/// * [num] is `null`, negative, or greater than `fc.features.length`
10+
FeatureCollection<T> sample<T extends GeometryObject>(
11+
FeatureCollection<T> fc,
12+
int num, {
13+
Random? random,
14+
}) {
15+
if (num < 0 || num > fc.features.length) {
16+
throw ArgumentError(
17+
'num must be between 0 and the number of features in the collection');
18+
}
19+
20+
final rnd = random ?? Random();
21+
final shuffled = List<Feature<T>>.from(fc.features);
22+
23+
// Partial Fisher-Yates: shuffle only the tail we need.
24+
for (var i = shuffled.length - 1; i >= shuffled.length - num; i--) {
25+
final j = rnd.nextInt(i + 1);
26+
final temp = shuffled[i];
27+
shuffled[i] = shuffled[j];
28+
shuffled[j] = temp;
29+
}
30+
31+
final selected = shuffled.sublist(shuffled.length - num);
32+
return FeatureCollection<T>(features: selected);
33+
}

lib/turf.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export 'polygon_to_line.dart';
3737
export 'polygonize.dart';
3838
export 'points_within_polygon.dart';
3939
export 'polyline.dart';
40+
export 'sample.dart';
4041
export 'square.dart';
4142
export 'transform.dart';
4243
export 'truncate.dart';

test/components/sample_test.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'dart:math';
2+
import 'package:test/test.dart';
3+
import 'package:turf/turf.dart';
4+
5+
void main() {
6+
test('sample picks the requested number of features', () {
7+
final points = FeatureCollection<Point>(features: [
8+
Feature<Point>(
9+
geometry: Point(coordinates: Position(1, 2)),
10+
properties: {'team': 'Red Sox'}),
11+
Feature<Point>(
12+
geometry: Point(coordinates: Position(2, 1)),
13+
properties: {'team': 'Yankees'}),
14+
Feature<Point>(
15+
geometry: Point(coordinates: Position(3, 1)),
16+
properties: {'team': 'Nationals'}),
17+
Feature<Point>(
18+
geometry: Point(coordinates: Position(2, 2)),
19+
properties: {'team': 'Yankees'}),
20+
Feature<Point>(
21+
geometry: Point(coordinates: Position(2, 3)),
22+
properties: {'team': 'Red Sox'}),
23+
Feature<Point>(
24+
geometry: Point(coordinates: Position(4, 2)),
25+
properties: {'team': 'Yankees'}),
26+
]);
27+
28+
// Pass a seeded RNG so the test is reproducible.
29+
final results = sample<Point>(points, 4, random: Random(42));
30+
31+
expect(results.features.length, equals(4),
32+
reason: 'should sample exactly 4 features');
33+
});
34+
}

0 commit comments

Comments
 (0)