-
Notifications
You must be signed in to change notification settings - Fork 87
Fix issue 355 added get frequency getter to iterable #357
Changes from 4 commits
ddcad5b
c2a7133
0c833d8
b444e37
1fe3d16
c5e18a2
8acd858
facd926
f4bbe43
9c4cf47
da963a5
2373566
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -601,6 +601,19 @@ extension IterableExtension<T> on Iterable<T> { | |
yield slice; | ||
} | ||
} | ||
|
||
/// Returns a map where the keys are the unique elements of the iterable | ||
/// and the values are the counts of those elements. | ||
/// | ||
/// For example, `['a', 'b', 'b', 'c', 'c', 'c'].countFrequency()` | ||
/// returns `{'a': 1, 'b': 2, 'c': 3}`. | ||
Map<T, int> countFrequency() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would probably make it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thank you, I agree this way is better, please check my changes |
||
var frequencyMap = <T, int>{}; | ||
for (var item in this) { | ||
frequencyMap[item] = (frequencyMap[item] ?? 0) + 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can use frequencyMap.update(item, _increment, ifAbsent: _one); with top-level/static helpers: int _increment(int value) => value + 1;
int _one() => 1; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thank you, I agree this way is better, please check my changes There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How expensive is a lookup? Shouldn't it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we are avoiding O(2) and lowering the constant factor. I hope, that assumes the map is actually implemented efficiently, but it's at least possible. Also, for degenerate cases, hash table lookup is linear. And quick-sort is quadratic. We always hope to not hit those cases, but when we do, it's better to have a low constant. For library code that other people will use, especially low-level code like this, efficiency is important. So when you provide code for others to depend on, to build their algorithms and applications on, you should never say "a constant factor doesn't matter", because to end users, the difference between 15ms and 17ms may be a missed animation frame, and that matters. (So, that's my pocket philosophy about writing code for others: The only person who can say whether performance is "good enough" is the application writer. A helper library doesn't know that. It may choose how it optimizes, for speed or size or a tradeoff, but it shouldn't say "it's good enough" and leave easy optimizations on the table. Every level below the application has to do their best and not be part of the problem.) The one thing we should actually do is to measure. If (I can see that I flip between pragmatic and ideological reasoning - be fast, because it matters, but don't be fast by doing it the wrong way, even if it is faster today. Tradeoffs. It's tradeoffs all the way down. So reasonable people can disagree on where to trade what. ) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not disagreeing, just wanted to understand the reasoning. Thanks for the explanation. (I actually didn't even know |
||
} | ||
return frequencyMap; | ||
} | ||
} | ||
|
||
/// Extensions that apply to iterables with a nullable element type. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
// for details. All rights reserved. Use of this source code is governed by a | ||
// BSD-style license that can be found in the LICENSE file. | ||
|
||
import 'dart:collection'; | ||
import 'dart:math' show Random, pow; | ||
|
||
import 'package:collection/collection.dart'; | ||
|
@@ -1352,6 +1353,84 @@ void main() { | |
expect(l3.toList(), [4, 5]); | ||
}); | ||
}); | ||
group('FrequencyCounter tests', () { | ||
test('should return correct frequency map for List of integers', () { | ||
var list = [1, 2, 2, 3, 3, 3]; | ||
var frequencyMap = list.countFrequency(); | ||
expect(frequencyMap, {1: 1, 2: 2, 3: 3}); | ||
}); | ||
|
||
test('should return correct frequency map for List of strings', () { | ||
var list = ['a', 'b', 'b', 'c', 'c', 'c']; | ||
var frequencyMap = list.countFrequency(); | ||
expect(frequencyMap, {'a': 1, 'b': 2, 'c': 3}); | ||
}); | ||
|
||
test('should handle empty List', () { | ||
var list = []; | ||
var frequencyMap = list.countFrequency(); | ||
expect(frequencyMap, {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider |
||
}); | ||
|
||
test('should handle single element List', () { | ||
var list = [42]; | ||
var frequencyMap = list.countFrequency(); | ||
expect(frequencyMap, {42: 1}); | ||
}); | ||
|
||
test('should return correct frequency map for Set of integers', () { | ||
// ignore: equal_elements_in_set | ||
var set = {1, 2, 2, 3, 3, 3}; | ||
var frequencyMap = set.countFrequency(); | ||
expect(frequencyMap, {1: 1, 2: 1, 3: 1}); | ||
}); | ||
|
||
test('should return correct frequency map for Set of strings', () { | ||
// ignore: equal_elements_in_set | ||
var set = {'a', 'b', 'b', 'c', 'c', 'c'}; | ||
var frequencyMap = set.countFrequency(); | ||
expect(frequencyMap, {'a': 1, 'b': 1, 'c': 1}); | ||
}); | ||
|
||
test('should handle empty Set', () { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would drop the tests for sets and queues unless there is a reason to believe that the implementation treats them differently (which it doesn't). We're not testing iteration, that is assumed to work, so all that matters is the sequence of values we get by iterating, and a (If we start trying to detect lists or sets, to do more efficient iteration or maybe assuming that sets cannot have duplicates so we don't need to count - which isn't true because sets can have non-standard equality - then there is reason to test with, and without, those types specifically.) |
||
var set = <int>{}; | ||
var frequencyMap = set.countFrequency(); | ||
expect(frequencyMap, {}); | ||
}); | ||
|
||
test('should handle single element Set', () { | ||
var set = {42}; | ||
var frequencyMap = set.countFrequency(); | ||
expect(frequencyMap, {42: 1}); | ||
}); | ||
|
||
test('should return correct frequency map for Queue of integers', () { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's probably overkill to go throguh all kinds of iterables. For example having elements that are equal, but not identical, or having elements that are records. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||
var queue = Queue<int>(); | ||
queue.addAll([1, 2, 2, 3, 3, 3]); | ||
var frequencyMap = queue.countFrequency(); | ||
expect(frequencyMap, {1: 1, 2: 2, 3: 3}); | ||
}); | ||
|
||
test('should return correct frequency map for Queue of strings', () { | ||
var queue = Queue<String>(); | ||
queue.addAll(['a', 'b', 'b', 'c', 'c', 'c']); | ||
var frequencyMap = queue.countFrequency(); | ||
expect(frequencyMap, {'a': 1, 'b': 2, 'c': 3}); | ||
}); | ||
|
||
test('should handle empty Queue', () { | ||
var queue = Queue<int>(); | ||
var frequencyMap = queue.countFrequency(); | ||
expect(frequencyMap, {}); | ||
}); | ||
|
||
test('should handle single element Queue', () { | ||
var queue = Queue<int>(); | ||
queue.add(42); | ||
var frequencyMap = queue.countFrequency(); | ||
expect(frequencyMap, {42: 1}); | ||
}); | ||
}); | ||
}); | ||
|
||
group('Comparator', () { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Single line first paragraph. Format as sentences.
Don't use
Returns
for a getter. (Don't start any DartDoc with it, there is always a better word).I'd say:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corrected