Dictionary keys in python - dictionary

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)

Related

How to iterate over whole array when I need i, j, k?

Given A is a multi-dimensional array, can I collapse iteration through every element into one for statement if I need i,j,k,etc.? In other words, I am looking for a more compact version of the following:
for k in 1:size(A,3)
for j in 1:size(A,2)
for i in 1:size(A,1)
# Do something with A[i+1,j,k], A[i,j+1,k], A[i,j,k+1], etc.
end
end
end
I think the solution is with axes or CartesianIndices, but I can't get the syntax right. Failed attempts:
julia> for (i,j,k) in axes(A)
println(i)
end
1
1
1
julia> for (i,j,k) in CartesianIndices(A)
println(i)
end
ERROR: iteration is deliberately unsupported for CartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`
It would be great if in addition to a solution which defines i,j,k, you could also provide a solution that works regardless of the number of dimensions in A.
You are almost there. Read the message carefully:
ERROR: iteration is deliberately unsupported for CartesianIndex.
It is the "pattern matching" in (i,j,k) in CartesianIndices(...) that fails, not the approach in general (I made the same mistake when reproducing the problem!). You have to convert the individual CartesianIndexes to tuples first:
julia> for ix in CartesianIndices(A)
println(Tuple(ix))
end
(1, 1, 1)
(2, 1, 1)
(3, 1, 1)
(1, 2, 1)
(2, 2, 1)
(3, 2, 1)
...
or using axes:
for (i,j,k) in Iterators.product(axes(x)...)
println([i,j,k]) # or whatever else you want
end

Robot in a Grid - how to get all possible paths

I'm trying to solve this problem:
There is a grid with with r rows and c columns. A robot sitting in top left cell can only move in 2 directions, right and down. But certain cells have to be avoided and the robot cannot step on them. Find a path for the robot from the top left to the bottom right.
The problem specifically asks for a single path, and that seems straight forward:
Having the grid as boolean[][], the pseudocode I have is
List<String> path = new ArrayList<String>()
boolean found = false
void getPath(r, c){
if (!found) {
if ( (r or c is outofbounds) || (!grid[r][c]) )
return
if (r==0 AND c==0) // we reached
found = true
getPath(r-1, c)
getPath(r, c-1)
String cell = "(" + r + ", " + c + ")"
path.add(cell)
}
}
Though I was wondering how can I get all the possible paths (NOT just the count, but the path values as well). Note that it has r rows and c columns, so its not a nxn grid. I'm trying to think of a DP/recursive solution but unable to come up with any and stuck. It's hard to think when the recursion goes in two ways.
Any pointers? And also any general help on how to "think" about such problems would be appreciated :).
Any pointers? And also any general help on how to "think" about such problems would be appreciated :).
Approach to the problem:
Mentally construct graph G of the problem. In this case the vertices are cells in the grid and directed edges are created where a valid robot move exist.
Search for properties of G. In this case G is a DAG (Directed Acyclic Graph).
Use such properties to come up with a solution. In this case (G is a DAG) its common to use topological sort and dynamic programming to find the amount of valid paths.
Actually you don't need to construct the graph since the set of edges is pretty clear or to do topological sort as usual iteration of the matrix (incremental row index and incremental column index) is a topological sort of this implicit graph.
The dynamic programming part can be solved by storing in each cell [x][y] the amount of valid paths from [0][0] to [x][y] and checking where to move next.
Recurrence:
After computations the answer is stored in dp[n - 1][m - 1] where n is amount of rows and m is amount of columns. Overall runtime is O(nm).
How about find all possible valid paths:
Usual backtracking works and we can speed it up by applying early pruning. In fact, if we calculate dp matrix and then we do backtracking from cell [n - 1][m - 1] we can avoid invalid paths as soon the robot enters at a cell whose dp value is zero.
Python code with dp matrix calculated beforehand:
n, m = 3, 4
bad = [[False, False, False, False],
[ True, True, False, False],
[False, False, False, False]]
dp = [[1, 1, 1, 1],
[0, 0, 1, 2],
[0, 0, 1, 3]]
paths = []
curpath = []
def getPath(r, c):
if dp[r][c] == 0 or r < 0 or c < 0:
return
curpath.append((r, c))
if r == 0 and c == 0:
paths.append(list(reversed(curpath)))
getPath(r - 1, c)
getPath(r, c - 1)
curpath.pop()
getPath(n - 1, m - 1)
print(paths)
# valid paths are [[(0, 0), (0, 1), (0, 2), (0, 3), (1, 3), (2, 3)],
# [(0, 0), (0, 1), (0, 2), (1, 2), (1, 3), (2, 3)],
# [(0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 3)]]
Notice that is very similar to your code, there is a need to store all valid paths together and take care that appended lists are a copy of curpath to avoid ending up with an list of empty lists.
Runtime: O((n + m) * (amount of valid paths)) since simulated robot moves belong to valid paths or first step into an invalid path detected using foresight (dp). Warning: This method is exponential as amount of valid paths can be .

Use one dictionary to fetch value in another dictionary

I have this problem where I have 2 dictionaries. One dict has keys representative of names (i.e. sample 1, sample 2, etc.) and the values are coordinates. The second dict has keys that are coordinates, and the values are data for each coordinate.
I need to build a 3rd dict that takes the names (keys), and then retrieves the respective values from the 2nd dict. As seen below:
dict1 = {32.0: [[(1, 7)], [(1, 17)], [(1, 8)], [(1, 18)]]}
dict2 = {(1, 7): 25.746392, (1, 18): 19.4782, (1, 17): 21.7492, (1, 8): 34.492}
dict3 = {32.0: [[25.746392], [21.7492], [34.492], [19.4782]]}
There are many more data points. I'm not sure if this is a simple problem, or if I'm having issues due to how nested the first dict is.
I'm still relatively new to Python, so any help is appreciated!
Two nested for-loops:
dict3 = dict1
for k in dict3.keys():
for i in range(len(dict3[k])):
dict3[k][i] = [dict2[dict3[k][i][0]]]
print dict3
Output:
{32.0: [[25.746392], [21.7492], [34.492], [19.4782]]}
One-liner:
dict3 = {k: [[dict2[dict1[k][i][0]]] for i in range(len(dict1[k]))] for k in dict1.keys()}

Indexing an array with a tuple

Suppose I have a tuple of (1, 2, 3) and want to index a multidimensional array with it such as:
index = (1, 2, 3)
table[index] = 42 # behaves like table[1][2][3]
index has an unknown number of dimensions, so I can't do:
table[index[0]][index[1]][index[2]]
I know I could do something like this:
functools.reduce(lambda x, y: x[y], index, table)
but it's utterly ugly (and maybe also inefficient), so I wonder if there's a better, more Pythonic choice.
EDIT: Maybe a simple loop is best choice:
elem = table
for i in index:
elem = elem[i]
EDIT2: Actually, there's a problem with both solutions: I can't assign a value to the indexed array :-(, back to ugly:
elem = table
for i in index[:-1]:
elem = elem[i]
elem[index[-1]] = 42
The question is very interesting and also your suggested solution looks good (havn't checked it, but this kind of problem requires a recursive treatment and you just did it in one line).
However, the pythonic way I use in my programs is to use dictionaries of tuples. The syntax is array-like, the performance - of a dictionary, and there was no problem in it for me.
For example:
a = {(1, 2, 3): 'A', (3, 4, 5): 'B', (5, 6, 7, 8): 'C'}
print a[1, 2, 3]
print a[5, 6, 7, 8]
Will output:
A
B
And assigning to an index is super easy:
a[1, 4, 5] = 42. (But you might want to first check that (1, 4, 5) is within the dict, or else it will be created by the assignment)

dynamic values in kwargs

I have a layer which helps me populating records from the form to tables and viceversa, it does some input checking, etc.
Now several methods of this layer which are called several times in different parts of the webform take the same parameters, so I wanted to pack them at the begining of the codefile.
kwargs(): return
{"tabla":"nombre_tabla","id":[hf_id.Value]
,"container": Panel1,"MsgBox1":
MsgBox1}
then I call
IA.search(**kwargs)
but doing that way the values of the dictionary get fixed with the ones they had in the begining, and one of them is retrieved from a webcontrol so it needs to be dynamic. So I wrapped them in a function
def kwargs(): return
{"tabla":"nombre_tabla",
"id":[hf_id.Value] ,"container":
Panel1,"MsgBox1": MsgBox1}
and then I call
IA.search(*kwargs())
IA.save(*kwargs())
etc.
and that way the value of the dictionary which comes from the webform (hf_id) is dynamic and not fixed. But I was wondering if in this case there is another way, a pythonic way, to get the values of the dictionary kwargs to be dynamic and not fixed
Python objects are pointers (though they are not directly manipulatable by the user.)
So if you create a list like this:
>>> a = [1, 2, 3]
and then store it in a dictionary:
>>> b = { 'key': a, 'anotherkey': 'spam' }
you will find modifications to the value in the dictionary also modify the original list:
>>> b['key'].append(4)
>>> print b['key']
[1, 2, 3, 4]
>>> print a
[1, 2, 3, 4]
If you want a copy of an item, so that modifications will not change the original item, then use the copy module.
>>> from copy import copy
>>> a = [1, 2, 3]
>>> b['key'] = copy(a)
>>> print b['key']
[1, 2, 3]
>>> b['key'].append(4)
>>> print b['key']
[1, 2, 3, 4]
>>> print a
[1, 2, 3]

Resources