I am using a Dictionary where the keys are strings and the values are integers. How can I get the key with the largest value out of this Dictionary?
I know there is the associationsDo: method I can use to iterate over both keys and values, but I don't know how to get the maximum value.
| countDict |
countDict := Dictionary new.
...
countDict associationsDo: [ :k :v | ??? ]
Here is a way to do it following your idea:
| max largest |
max := nil.
countDict associationsDo: [:k :v |
(max isNil or: [v > largest])
ifTrue: [
max := k.
largest := v]].
^max
Here is another way, shorter but not very efficient:
countDict isEmpty ifTrue: [^nil].
^countDict keyAtValue: countDict max
Also, if you have a countDict I suspect that it represents the number of occurrences of every key. If that is the case you shouldn't be using a Dictionary but a Bag. Instances of Bag represent collections of objects which may have several occurrences each. Examples:
names := Bag new.
people do: [:person | names add: person firstName].
and you may end up with
2 occurrences of 'John'
1 occurrence of 'Paul'
4 occurrences of 'Ringo'
7 occurrences of 'George'
names occurrencesOf: 'John' ----> 2
The Bag will internally have a countDict sort of Dictionary, but to your model a Bag could reveal better your intention than a Dictionary because you will only need to add: elements without having to count them; the Bag will do it for you.
With a Bag your computation becomes
bag occurrencesOf: bag asSet max
The reason to send asSet is to avoid iterating several times on every value, which would happen if we simply put bag max. This simpler code will also work, but given that max iterates using do: and Bag implements do: by repeating the evaluation of the block for every occurrence of the element, this solution would be less efficient.
A better approach would be to re-implement max (and min) in Bag so that each element is iterated once. This would be similar to the code that we have above which followed your initial idea (associationsDo: [...). But let's leave the details of this as an exercise for the reader.
Anyway, if we re-implemnted max in Bag, the code would become simple and efficient at once:
bag occurrencesOf: bag max
Another nice way to do this:
(countDict associations detectMax: #value) key
Related
In Redis, let's say I have a set called animals.
127.0.0.1:6379> sadd animals cat:bob cat:fred dog:joe dog:rover hamster:harvey
I know I can use SRANDMEMBER to pull a random member from the set, which might be any of the values.
And I know I can get all cats out of the set with something like SSCAN animals 0 MATCH cat:*
But is there a way to retrieve a random cat?
Edit for clarity: My example has the important designator at start of string, but I'm looking for something that follows a general pattern where the "match" might be anywhere within the string.
Not in a single command. If you are using a Sorted Set, you can get ranges of values based on the lexical content:
> ZADD animals 0 cat:bob 0 cat:fred 0 dog:joe 0 dog:rover 0 hamster:harvey
> ZRANGESTORE cats animals [cat: (cau BYLEX
> ZRANDMEMBER cats
> DEL cats
Note that [cat: means "range staring with cat, inclusive" and (cau means "range ending with cau, exclusive". I picked "cau" because it would be next in the sequence and would only pick cats.
This is, admittedly, a bit of a hack. 😉
I would like to use an array rows for indexing rows of another array x. Initially, rows contains indices of all rows of x (and is therefor sorted). Throughout the program, some indices exclude are chosen to be removed from rows. Similar to rows itself, exclude is a sorted array.
What is the best way of finding the set difference of rows and exclude?
I have thought of a few different options, but I think their complexities are more than O(n + m), where n is the length of rows and m is the length of exclude.
new_rows = [r for r in rows if r not in exclude]
This solutions requires looking up exclude every time and therefore, O(mn) complexity.
new_rows = setdiff1d(rows, exclude, assume_unique=True)
This will probably take O(nlogm), but I'm not sure.
Convert exclude to a dict and run 1. The problem with this approach is that it requires extra memory, but it meets the complexity requirement.
Here are outlines of two O(n+m) options:
1) heapq.merge will combine two sorted sequences in linear time. As the combined sequence is sorted, shared indices will sit next to each other.
2) as rows as you describe it is a "thinned out range" I assume that the the max value of rows is not excessively large. You can therfore allocate an array E of that size (O(1) if we don't initialize it, i.e. use np.empty). Then you use rows and exclude to index into the empty array. For example, you write E[rows] = 1 E[exclude] = 0 and then check back E[rows] and remove all elements of rows at which E has changed from 1 to 0.
Option 2 also works if the two sets are not sorted.
I have a 2-dimensional int array, and I'd like to get the 2nd element from every array in the 2nd dimension. So for example, I'd like to get 2,4, and 6 from the array literal '{{1,2},{3,4},{5,6}'. Is this possible? I've searched the docs but I haven't found anything that can do what I want.
unnest(arr[:][2:2]) will give you a table expression for what you want (where arr is the name of your array column)
If you want to get a 1 dimensional array of those elements, you can use array(select * from unnest(arr[:][2:2])) (because arr[:][2:2] is still a 2 dimensional one).
http://rextester.com/VLOJ18858
I have a class that has 3 properties: Name, ID, and ParentID.
My data:
Name ID ParentID
Event A 1 1
Event B 2 1
Event C 3 1
Event D 4 2
I have everything in a List and was trying to use the OrderBy or perhaps the Sort methods. Not sure which would be better.
I need the data in the list to be ordered so that an event has it's child as the next item in the list. Any help on this would be greatly appreciated, I am doing this in VB by the way. Thanks!!
You can sort the list like this
list.Sort(Function(x, y) 2 * x.ParentID.CompareTo(y.ParentID) + _
x.ChildID.CompareTo(y.ChildID))
Explanation: I am using a lambda expression here. You can think of it as a kind of inline declaration of a function. CompareTo returns either -1, 0 or +1. A negative number means x is less than y, 0 both are equal and +1 means x is greater than y. By multiplying the first comparison by two, its sign takes precedence over the second comparison. The second has only an effect, if the first one returns 0.
The advantage of using the lists Sort method over LINQ is that the list is sorted in-place. With LINQ you would have to create a new list.
I have 3 NSArrays with:
item: amount
A: 1
B: 2
C: 3
A: 2
E: 1
F: 6
C: 5
D: 1
F: 3
After "combining" these into one, I need:
A: 3
B: 2
C: 8
D: 1
E: 1
F: 9
Do I first combine all the arrays into one and then sum and remove the duplicates?
You could use an NSCountedSet. I'm not clear on the structure of the data in your arrays, but by assuming that your B: 2 means that you have two B's in the array, then something like this would work:
NSCountedSet *set = [NSCountedSet setWithCapacity:[array1 count]+[array2 count]+[array3 count]];
[set addObjectsFromArray:array1];
[set addObjectsFromArray:array2];
[set addObjectsFromArray:array3];
// Test it out!
NSUInteger countForC = [set countForObject:objC];
// countForC == 8
Instead of using a NSArray you could try using a NSMutableDictionary where the key is inherent in the objects structure. That will allow you to iterate through each of your arrays of letters and counts then query for the value with the key, get the value and add to the value, then continue processing.
One possibility would be to use:
Use predicates to extract like sets of data (by item) into separate arrays. See Collection predicates guide
Key Value Coding to sum the value field of each of the resulting arrays (by item). See KVO collection operators.
Pop the results in whatever structure you like (NSArray or NSDictionary).
There may be performance considerations to explore. Alternatively, iterate the array, pulling out matching items in a separate NSDictionary (keyed on item) and summing as you go.