My actual case is more complicated, but the MVCE is
from typing import List
def find_largest(numbers: List[int]) -> List[int]:
"""
>>> find_largest([3, 4, 5, 5, 3, 1, -2, 4, 3, 3])
[5, 5]
"""
assert len(numbers) > 0 # guaranteed by caller
largest_numbers = None
value = None
for number in numbers:
if value is None or number > value:
largest_numbers = [number]
value = number
elif number == value:
largest_numbers.append(number)
return largest_numbers
if __name__ == '__main__':
import doctest
doctest.testmod()
When I run mypy on this, I get:
mytest.py:18: error: Incompatible return value type (got "Optional[List[int]]", expected "List[int]")
Found 1 error in 1 file (checked 1 source file)
But restrictions which are not captured by mypy guarantee that None is not returned. How can I hint that to mypy? (Initializing with something else is NOT possible)
Your code can still return None according to Mypy and the it thinks the typing is correct.
Assuming you can't fix this you could also force the return to always have a value with:
assert largest_numbers
return largest_numbers
Alternatively, use typing.cast:
To the type checker this signals that the return value has the designated type, but at runtime we intentionally don’t check anything (we want this to be as fast as possible).
from typing import List, cast
...
def find_largest(numbers: List[int]) -> List[int]:
"""
>>> find_largest([3, 4, 5, 5, 3, 1, -2, 4, 3, 3])
[5, 5]
"""
assert len(numbers) > 0 # guaranteed by caller
largest_numbers = None
value = None
for number in numbers:
if value is None or number > value:
largest_numbers = [number]
value = number
elif number == value:
largest_numbers.append(number)
return cast(List[int], largest_numbers)
...
Related
Let's say I have a vector, the values are from 1 to 10. I want that if you find 5 and 5 next to each other, remove them together with the next elements.
input
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]
expected output
[1, 2, 3, 4]
This was my attempt. I'm finding index to remove, but borrowing rules are making me stuck.
let mut element = vec![1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10];
for (index, val) in element.iter().enumerate() {
if *val == 5 {
if let Some(next_val) = element.get(index + 1) {
if *next_val == 5 {
//element.drain(index..);
}
}
}
}
Rust is saving you from iterator invalidation (a common source of bugs in other languages). This is an error that usually happens when you try to modify a data structure while concurrently iterating over it. You cannot move on to the (now-deleted) next element after calling element.drain(index..). So you need to add a break after that point to avoid memory unsafety.
In this case just adding break; is sufficient to make the code compile. However, for a more concise, linear solution, take full advantage of the iterators and methods provided by the standard library:
if let Some(index) = element.windows(2).position(|pair| pair[0] == pair[1]) {
element.truncate(index);
}
windows(2) on a slice gives an iterator over subslices of length 2, and the position call returns the index of the first element of that iterator for which the two elements of the slice are equal. (If no such pair exists, position returns None.)
I find that the position closure becomes more obvious with the (currently unstable) array_windows feature:
if let Some(index) = element.array_windows().position(|[x, y]| x == y) {
element.truncate(index);
}
Playground
Related
is it possible to filter on a vector in-place?
You can't do what you want to do because you want to remove some elements from a vector while you are iterating it. And this is a big mistake. Note that removing any elements from a vector invalidates the iterators, hence you will access unexpected locations so rust doesn't allow UBs
You can use something like the following
let mut elements = vec![1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10];
let mut first_repeated_five_index_op = None;
for index in 0..elements.len()-1{
if elements[index] == 5 && elements[index + 1] == 5{
first_repeated_five_index_op = Some(index);
break;
}
}
if let Some(first_repeated_five_index) = first_repeated_five_index_op{
elements.truncate(first_repeated_five_index);
}
println!("{:?}", elements);
See a Demo
Could it be possible to write in FFL a version of filter that stops filtering after the first negative match, i.e. the remaining items are assumed to be positive matches? more generally, a filter.
Example:
removeMaxOf1([1,2,3,4], value>=2)
Expected Result:
[1,3,4]
This seems like something very difficult to write in a pure functional style. Maybe recursion or let could acheive it?
Note: the whole motivation for this question was hypothesizing about micro-optimizations. so performance is very relevant. I am also looking for something that is generally applicable to any data type, not just int.
I have recently added find_index to the engine which allows this to be done easily:
if(n = -1, [], list[:n] + list[n+1:])
where n = find_index(list, value<2)
where list = [1,2,3,4]
find_index will return the index of the first match, or -1 if no match is found. There is also find_index_or_die which returns the index of the first match, asserting if none is found for when you're absolutely certain there is an instance in the list.
You could also implement something like this using recursion:
def filterMaxOf1(list ls, function(list)->bool pred, list result=[]) ->list
base ls = []: result
base not pred(ls[0]): result + ls[1:]
recursive: filterMaxOf1(ls[1:], pred, result + [ls[0]])
Of course recursion can! :D
filterMaxOf1(input, target)
where filterMaxOf1 = def
([int] l, function f) -> [int]
if(size(l) = 0,
[],
if(not f(l[0]),
l[1:],
flatten([
l[0],
recurse(l[1:], f)
])
)
)
where input = [
1, 2, 3, 4, ]
where target = def
(int i) -> bool
i < 2
Some checks:
--> filterOfMax1([1, ]) where filterOfMax1 = [...]
[1]
--> filterOfMax1([2, ]) where filterOfMax1 = [...]
[]
--> filterOfMax1([1, 2, ]) where filterOfMax1 = [...]
[1]
--> filterOfMax1([1, 2, 3, 4, ]) where filterOfMax1 = [...]
[1, 3, 4]
This flavor loses some strong type safety, but is nearer to tail recursion:
filterMaxOf1(input, target)
where filterMaxOf1 = def
([int] l, function f) -> [int]
flatten(filterMaxOf1i(l, f))
where filterMaxOf1i = def
([int] l, function f) -> [any]
if(size(l) = 0,
[],
if(not f(l[0]),
l[1:],
[
l[0],
recurse(l[1:], f)
]
)
)
where input = [
1, 2, 3, 4, ]
where target = def
(int i) -> bool
i < 2
My coin change dynamic programming implementation is failing for some of the test cases, and I am having a hard time figuring out why:
Problem Statement: Given an amount and a list of coins, find the minimum number of coins required to make that amount.
Ex:
Target Amount: 63
Coin List: [1, 5, 10, 21, 25]
Output: [21, 21, 21]
def coin_change(change_list, amount, tried):
if amount <= 0:
return []
if amount in change_list:
return [amount]
if amount in tried:
return tried[amount]
coin_count = []
for change in change_list:
if change < amount:
changes = coin_change(change_list, amount-change, tried)
changes.append(change)
coin_count.append(changes)
min_changes = coin_count[0][:]
for x in coin_count[1:]:
if len(min_changes) >= len(x):
min_changes = x[:]
tried[amount] = min_changes[:]
return min_changes
def main():
for amount in range(64):
changes = coin_change([1, 5, 10, 21, 25], amount, {})
if sum(changes) != amount:
print "WRONG: Change for %d is: %r" % (amount, changes)
else:
# print "Change for %d is: %r" % (amount, changes)
pass
if __name__ == "__main__":
main()
Trinket: https://trinket.io/python/43fcff035e
You're corrupting the variable, changes, by appending to it during a loop. Try this:
Replace these two lines:
changes.append(change)
coin_count.append(changes)
With:
_changes = changes[:] + [change]
coin_count.append(_changes)
I am having trouble writing python code to print how many available seats there are in a row. I have a simple set of nested dictionaries - what I need to add is a test to see how many consecutive keys == available. the output needs to be something like, 'there is a block of 4 seats available together'.
seats = {'A': ['available', 'unavailable','available','available','available'],
'B': ['unavailable', 'unavailable','available','available','available'],
'C': ['available', 'unavailable','unavailable','available','available'],
'D': ['available', 'unavailable','available','unavailable','unavailable']}
Is there a very simple method of counting how many items in a row have the same value? I am literally brand new to programming, so I really need explanation of how code is working as well.
One way -- which may seem over-powered for this problem, but it's a handy tool to learn -- is to use itertools.groupby. Its job is to group consecutive terms of a sequence together, which is exactly what you want to do here. For example, if we had a list made of up 1 and 2:
>>> from itertools import groupby
>>> groupby([1,2,2,1,2,2,2,1,1,2])
<itertools.groupby object at 0x8ee793c>
>>> [(key, list(group)) for key, group in groupby([1,2,2,1,2,2,2,1,1,2])]
[(1, [1]), (2, [2, 2]), (1, [1]), (2, [2, 2, 2]), (1, [1, 1]), (2, [2])]
We can make a list of key-value pairs where the groups are the value. (Really they're an iterable grouper object, so we have to take the list to materialize them to see them.)
So in your case:
>>> groupby(seats["A"])
<itertools.groupby object at 0x8ee7e64>
>>> [(k, list(g)) for k,g in groupby(seats["A"])]
[('available', ['available']), ('unavailable', ['unavailable']), ('available', ['available', 'available', 'available'])]
>>> [len(list(g)) for k,g in groupby(seats["A"]) if k == 'available']
[1, 3]
>>> max(len(list(g)) for k,g in groupby(seats["A"]) if k == 'available')
3
With a little more work we could get the locations too, if those were significant. We can use enumerate to give the seats numbers:
>>> list(enumerate(seats["A"]))
[(0, 'available'), (1, 'unavailable'), (2, 'available'), (3, 'available'), (4, 'available')]
And then group these instead, using the key parameter to groupby to tell it we want to group on the second term (index #1), the available/unavailable state, not the number:
>>> grouped = groupby(enumerate(seats["A"]), key=lambda x: x[1])
and then extract the contiguous available seats:
>>> avail = [list(g) for k,g in grouped if k == 'available']
>>> avail
[[(0, 'available')], [(2, 'available'), (3, 'available'), (4, 'available')]]
From this we can do all sorts of things.
>>> min(avail, key=len) # one of the smallest groups
[(0, 'available')]
>>> max(avail, key=len) # one of the largest groups
[(2, 'available'), (3, 'available'), (4, 'available')]
>>> max(avail, key=len)[0][0] # start of largest
2
>>> next(g for g in avail if len(g) >= 2)
[(2, 'available'), (3, 'available'), (4, 'available')]
Here's a quick and dirty code block that should help get you started:
if rowChoice not in seats:
# Tell the user they entered a bad row and keep prompting them for input until it works
max_available = 0
available = 0
for chair in seats[rowChoice]:
# When a seat is taken, update the maxium number of available seats and reset our counter
if chair != "available":
if available > max_available:
max_available = available
available = 0
else:
available += 1
print "There is a maximum block of %d seats available" % (max_available)
What is the most concise way of converting a java.util.List into a normal
JavaFX sequence (in JavaFX)?
e.g.
def myList = java.util.Arrays.asList(1, 2, 3);
def mySequence = ... // a sequence containing [1, 2, 3]
This is the most concise way I could find - there may be a more direct method though
def myList = java.util.Arrays.asList(1, 2, 3);
def mySequence = for (i in myList) i;
println("mySequence={mySequence}");