I'm trying to parse a tuple of the form:
a=(1,2)
or
b=((1,2), (3,4)...)
where for a's case the code would be:
x, y = a
and b would be:
for element in b:
x, y = element
is there an fast and clean way to accept both forms? This is in a MIDI receive callback
(x is a pointer to a function to run, and y is intensity data to be passed to a light).
# If your input is in in_seq...
if hasattr(in_seq[0], "__iter__"):
# b case
else:
# a case
This basically checks to see if the first element of the input sequence is iterable. If it is, then it's your second case (since a tuple is iterable), if it's not, then it's your first case.
If you know for sure that the inputs will be tuples, then you could use this instead:
if isinstance(in_seq[0], tuple):
# b case
else:
# a case
Depending on what you want to do, your handling for the 'a' case could be as simple as bundling the single tuple inside a larger tuple and then calling the same code on it as the 'b' case, e.g...
b_case = (a_case,)
Edit: as pointed out in the comments, a better version might be...
from collections import Iterable
if isinstance(in_seq[0], Iterable):
# ...
The right way to do that would be:
a = ((1,2),) # note the difference
b = ((1,2), (3,4), ...)
for pointer, intensity in a:
pass # here you do what you want
Related
I have a list stored in this format: [(int, (int, int)), ...]
My code looks like this for the first case.
heap.heappush(list_, (a, b)) # b is a tuple
while len(list_):
temp = heap.heappop(list_)[1]
Now my ideal implementation would be
list_.append(a, b) # b is a tuple
while len(list_):
list_.sort(key = lambda x: x[0])
temp = list_.pop(0)[1]
The second implementation causes issues in other parts of my code. Is there any reason the second is incorrect, and how could I correct it to work like the heapq
EDIT: I know heappop() pops the smallest value out, which is why I have sorted the list based off of the 'a' (which heappop uses too, I assume)
To work with heapq you have to be aware python implements min heaps. That means the element at index 0 is always the smallest.
Here is what you want implemented with heapq:
import heapq
from typing import Tuple
class MyObject:
def __init__(self, a: int, b: Tuple(int, int)):
self.a = a
self.b = b
def __lt__(self, other):
return self.a < other.a
l = [MyObject(..,..), MyObject(..,..),..,MyObject(..,..)] # your list
heapq.heapify(l) # convert l to a heap
heapq.heappop(l) # retrieves and removes the smallest element (which lies at index 0)
# After popping the smallest element, the heap internally rearranges the elements to get the new smallest value to index 0. I.e. it maintaines the "heap variant" automatically and you don't need to explicitly sort!
Notice:
I didn't need to sort. The heap is by nature a semi-sorted structure
I needed to create a dedicated class for my objects. This is cleaner than working with tuples of tuples and also allowed me to override less than lt so that the heap knows how to create the tree internally
Here is more detailed info for the avid reader :D
When you work with heaps then you shouldn't need to explicitly sort. A heap by nature is a semi-sorted topology that (in the case of python heapq) keeps the smallest element at index 0. You don't however, see the tree structure underneath (remember, a heap is a tree in whicheach parent node is smaller than all its children and descendants).
Moreover, you don't need to append the elements one by one. Rather use heapq.heapify(). This will also ensure that no redundant heapify-up/heapify-down operations. Otherwise, you will have a serious run time issue if your list is huge :)
I have a list of dictionaries as below,
test = [{'a':100, 'b':1, 'd':3.2},
{'a':200, 'b':5, 'd':8.75},
{'a':500, 'b':2, 'd':6.67},
{'a':150, 'b':7, 'd':3.86},
{'a':425, 'b':2, 'd':7.72},
{'a':424, 'b':2, 'd':7.72}]
Given a 'b' value, I need to find the maximum value of 'd' and extract the corresponding value of 'a' in that dictionary. If there's a tie, then take the highest value of 'a'. e.g. {a:424, b:2, d:7.72} and {a:424, b:2, d:7.72} has b = 2 and their corresponding d values are equal. In that case, I return a = 425.
Following code runs alright. However, I would like to know possible ways to optimise this or to use an anonymous function (lambda) to solve this.
def gerMaxA(bValue):
temporary_d = -999.99
temporary_a = 0
for i in test:
if i['b'] == bValue:
if i['d'] > temporary_d:
temporary_a = i['a']
temporary_d = i['d']
elif i['d'] == temporary_d:
if i['a'] >= temporary_a:
temporary_a = i['a']
ans = (temporary_a, temporary_d)
return ans
Appreciate any insights.
However, I would like to know possible ways to optimise this or to use an anonymous function (lambda) to solve this.
"Optimise" is a red herring - you cannot simple "optimise" something in a void, you must optimise it for some quality (speed, memory usage, etc.)
Instead, I will show how to make the code simpler and more elegant. This is theoretically off-topic for Stack Overflow, but IMX the system doesn't work very well if I try to send people elsewhere.
Given a 'b' value
This means that we will be selecting elements of the list that meet a condition (i.e., the 'b' value matches a target). Another word for this is filtering; while Python does have a built-in filter function, it is normally cleaner and more Pythonic to use a comprehension or generator expression for this purpose. Since we will be doing further processing on the results, we shouldn't choose yet.
I need to find the maximum value of 'd'
More accurately: you see the element which has the maximum value for 'd'. Or, as we like to think of it in the Python world, the maximum element, keyed by 'd'. This is built-in, using the max function. Since we will feed data directly to this function, we don't care about building up a container, so we will choose a generator expression for the first step.
The first step looks like this, and means exactly what it says, read left to right:
(element for element in test if element['b'] == b_value)
"A generator (()) producing: the element, for each element found in test, but only including it if the element's ['b'] value is == b_value".
In the second step, we wrap the max call around that, and supply the appropriate key function. This is, indeed, where we could use lambda:
max(
(element for element in test if element['b'] == b_value),
key=lambda element:(element['d'], element['a'])
)
The lambda here is a function that transforms a given element into that pair of values; max will then compare the filtered dicts according to what value is produced by that lambda for each.
Alternately, we could use a named function - lambdas are the same thing, just without a name and with limits on what can be done within them:
def my_key(element):
return element['d'], element['a']
# and then we do
max((element for element in test if element['b'] == b_value), key=my_key)
Or we could use the standard library:
from operator import itemgetter
max((element for element in test if element['b'] == b_value), key=itemgetter('d', 'a'))
The last step, of course, is simply to extract the ['a'] value from the max result.
Here's an approach that uses built-ins:
In [1]: from operator import itemgetter
In [2]: def max_a_value(b_value, data):
...: matching_values = (d for d in data if d['b'] == b_value)
...: return max(matching_values, key=itemgetter('d','a'))['a']
...:
In [3]: test = [{"a":100, "b":1, "d":3.2},
...: {"a":200, "b":5, "d":8.75},
...: {"a":500, "b":2, "d":6.67},
...: {"a":150, "b":7, "d":3.86},
...: {"a":425, "b":2, "d":7.72},
...: {"a":424, "b":2, "d":7.72}]
In [4]: max_a_value(2, test)
Out[4]: 425
Note, this isn't more algorithmically efficient. Both are O(N)
Yes, you can optimize this. With the given specifications, there is no reason to retain inferior entries. There is also no particular reason to keep this as a list of dictionaries. Instead, make this a simple data frame or reference table. The key is the 'b' value; the value is the desired 'a' value.
Make one pass over your data to convert to a single dict:
test = [ {
1: 100,
2: 425,
5: 200,
7: 150 } ]
There's your better data storage; you've already managed one version of conversion logic.
May be you want to check this. I don't know if it is more efficient but at least looks pythonic:
def gerMaxA(bValue):
dict = {i:x['d'] for i, x in enumerate(test) if x['b']== bValue}
idx = max(dict, key=dict.get)
max_d = test[idx]['d']
dict_a = {k :test[k]['a'] for k in dict.keys() if dict[k] == max_d}
idx_a = max(dict_a, key = dict_a.get)
return test[idx_a]['a'], test[idx]['d']
The last three lines of code make sure that it'll take the greater 'a' value in the case there were many of them.
First off I'm using python.
I have a list of items called tier1 it looks like this.
tier1 = ['a1','a2,'a3',..,'an']
I have 2 functions called functionA and functionZ.
They both take a string as their argument and produce a list output like this. The lists must be produced during execution time and are not available from the start. Only tier1 is available.
listOutput = functionA(tier1[0]).
listOutput looks like this
listOutput = ['b1','b2,'b3',..,'bn']
The next time functionA is used on listOutput lets say item 'b1', it will produce
listOutput = functionA('b1')
output:
listOutput = ['bc1','bc2,'bc3',..,'bcn']
This time when functionA is used, on lets say 'bc1', it might come up empty, so functionZ is used on 'bc1' is used instead and the output is stored somewhere.
listOutput = functionA('bc1')
output
listOutput = []
So I use
listOutput = functionZ('bc1')
output
listOutput = ['series1','series2','series3',....,'seriesn']
Now I have to go back and try bc2, until bcn doing the same logic. Once that's done, I will use functionA on 'b2'. and so on.
The depth of each item is variable.
It looks something like this
As long as listOutput is not empty, functionA must be used on the listOutput items or tier1 items until it comes up empty. Then functionZ must be used on whichever item in the list on which functionA comes up empty.
After tier1, listOutput will also always be a list, which must also be cycled through one by one and the same logic must be used.
I am trying to make a recursive function based on this but I'm stuck.
So far I have,
def recursivefunction (idnum): #idnum will be one of the list items from tier1 or the listOutputs produced
listOutput = functionA(idnum)
if not listOutput:
return functionZ(idnum)
else:
return recursivefunction(listOutput)
But my functions return lists, how do I get them to go deeper into each list until functionZ is used and once it's used to move on to the next item in the list.
Do I need to create a new kind of data structure?
I have no idea where to start, should I be looking to create some kind of class with linked lists?
The way I understand your problem:
there is an input list tier1, which is a list of strings
there are two functions, A and Z
A, when applied to a string, returns a list of strings
Z, when applied to a string, returns some value (type is unclear, assume list of string as well)
the algorithm:
for each element of tier1, apply A to the element
if the result is an empty list, apply Z to the element instead, no further processing
otherwise, if the result is not empty, apply the algorithm on the list
So, in Python:
from random import randint
# since you haven't shared what A and Z do,
# I'm just having them do random stuff that matches your description
def function_a(s):
# giving it a 75% chance to be empty
if randint(1, 4) != 1:
return []
else:
# otherwise between 1 and 4 random strings from some selection
return [['a', 'b', 'c'][randint(0, 2)] for _ in range(randint(1,4))]
# in the real case, I'm sure the result depends on `s` but it doesn't matter
def function_z(s):
# otherwise between 0 and 4 random strings from some selection
return [['x', 'y', 'z'][randint(0, 2)] for _ in range(randint(0,4))]
def solution(xs):
# this is really the answer to your question:
rs = []
for x in xs:
# first compute A of x
r = function_a(x)
# if that's the empty list
if not r:
# then we want Z of x instead
r = function_z(x)
else:
# otherwise, it's the same algorithm applied to all of r
r = solution(r)
# whatever the result, append it to rs
rs.append(r)
return rs
tier1 = ['a1', 'a2', 'a3', 'a4']
print(solution(tier1))
Note that function_a and function_z are just functions generating random results with the types of results you specified. You didn't share what the logic of A and Z really is, so it's hard to verify if the results are what you want.
However, the function solution does exactly what you say it should - if I understand you somewhat complicated explanation of it correctly.
Given that the solution to your question is basically this:
def solution(xs):
rs = []
for x in xs:
r = function_a(x)
if not r:
r = function_z(x)
else:
r = solution(r)
rs.append(r)
return rs
Which can even be rewritten to:
def solution_brief(xs):
return [function_z(r) if not r else solution(r) for r in [function_a(x) for x in xs]]
You should reexamine your problem description. The key with programming is understanding the problem and breaking it down to its essential steps. Once you've done that, code is quick to follow. Whether you prefer the first or second solution probable depends on experience and possibly on tiny performance differences.
By the way, any solution written as a recursive function, can also be written purely iterative - that's often preferable from a memory and performance perspective, but recursive functions can have the advantage of being very clean and simple and therefore easier to maintain.
Putting my coding where my mouth is, here's an iterative solution of the same problem, just for fun (not optimal by any means):
def solution_iterative(xs):
if not xs:
return xs
rs = xs.copy()
stack_rs = [rs]
stack_is = [0]
while stack_rs:
r = function_a(stack_rs[-1][stack_is[-1]])
if not r:
stack_rs[-1][stack_is[-1]] = function_z(stack_rs[-1][stack_is[-1]])
stack_is[-1] += 1
else:
stack_rs[-1][stack_is[-1]] = r
stack_rs.append(r)
stack_is.append(0)
while stack_is and stack_is[-1] >= len(stack_rs[-1]):
stack_is.pop()
stack_rs.pop()
if stack_is:
stack_is[-1] += 1
return rs
I am trying to evaluate power series using python. series => e^x = 1+ x+ x^2/2! + x^3/3!...x^n/n!
I am getting this error ''int' object has no attribute 'extend'.
My code:
import math
print('give x')
x = float(input())
n =100
k = 0
list = (1)
while 0<x<1:
list.extend([math.pow(x,K+1))])
k = k+1
if x==n:
break
print(sum(list))
Please help!
There are multiple problems with your code.
Firstly, you are attempting to create a list with (1) - that just creates the integer object 1, the parentheses have no effect here. To create a list containing 1 you need [1]. And you shouldn't use the names of Python built-ins (like list) as variable names - not only is it confusing to other people who may read your code it makes the built-in inaccessible, which can lead to mysterious bugs.
K is not the same as k.
Your while 0<x<1: test does't make much sense; FWIW, the Taylor series for ex converges for all values of x.
Your if x==n: test should be if k==n:, although it'd be better to use a for loop with range (or maybe xrange in Python 2).
You don't need to save the terms in a list - just add them as you go.
You don't need math.pow - x**k calculates the same thing as math.pow(x, k), but even that's unnecessary here: you should just keep track of the previous term and multiply it by x on each loop.
You forgot the /n!. Once again, you don't really need to compute the factorial (or call the math.factorial function) since you can just divide the previous term by k.
Hopefully, that's given you enough clues to fix your code. I won't provide working code at this stage, since I suspect this is a homework problem. Note that the math module has an exp function which you can use to test the accuracy of your power series calculations.
A list literal is created with square brackets, []. You can use parentheses, (), for grouping or for creating a tuple. In the case of list = (1), they are being used for grouping, so this is the same as list = 1. (A tuple with one element is created with mytuple = (1,) or just mytuple = 1,.)
At this point, I'll mention that naming one of your variables list masks the built-in function list, so after you do that you can't access that function anymore without some effort. It's best to name your object something else, like lst.
A list's extend() method adds all the elements from the passed list onto the object you're accessing, so if mylist was [1, 2, 3], mylist.extend([4, 5]) would result in mylist becoming [1, 2, 3, 4, 5]. However, you only have one object to add, so it makes more sense to use append(), which adds the passed object to the given list.
x = float(input('Give x: ')) # the input function can be passed a prompt string
n = 100
k = 0
lst = [1] # changed name, created a list
while 0<x<1:
list.append(x**(k+1)) # you can just use the ** operator if you want
# also, k isn't K
k = k+1
if x==n: # x is never changed, so your loop either never runs
# or goes forever
break
print(sum(lst))
Note the while loop that will either never be entered or never finish. You'll have to take another look at your program's logic.
When a Python list is known to always contain a single item, is there a way to access it other than:
mylist[0]
You may ask, 'Why would you want to?'. Curiosity alone. There seems to be an alternative way to do everything in Python.
Raises exception if not exactly one item:
Sequence unpacking:
singleitem, = mylist
# Identical in behavior (byte code produced is the same),
# but arguably more readable since a lone trailing comma could be missed:
[singleitem] = mylist
Rampant insanity, unpack the input to the identity lambda function:
# The only even semi-reasonable way to retrieve a single item and raise an exception on
# failure for too many, not just too few, elements as an expression, rather than a
# statement, without resorting to defining/importing functions elsewhere to do the work
singleitem = (lambda x: x)(*mylist)
All others silently ignore spec violation, producing first or last item:
Explicit use of iterator protocol:
singleitem = next(iter(mylist))
Destructive pop:
singleitem = mylist.pop()
Negative index:
singleitem = mylist[-1]
Set via single iteration for (because the loop variable remains available with its last value when a loop terminates):
for singleitem in mylist: break
There are many others (combining or varying bits of the above, or otherwise relying on implicit iteration), but you get the idea.
I will add that the more_itertools
library has a tool that returns one item from an iterable.
from more_itertools import one
iterable = ["foo"]
one(iterable)
# "foo"
In addition, more_itertools.one raises an error if the iterable is empty or has more than one item.
iterable = []
one(iterable)
# ValueError: not enough values to unpack (expected 1, got 0)
iterable = ["foo", "bar"]
one(iterable)
# ValueError: too many values to unpack (expected 1)
more_itertools is a third-party package > pip install more-itertools
(This is an adjusted repost of my answer to a similar question related to sets.)
One way is to use reduce with lambda x: x.
from functools import reduce
> reduce(lambda x: x, [3]})
3
> reduce(lambda x: x, [1, 2, 3])
TypeError: <lambda>() takes 1 positional argument but 2 were given
> reduce(lambda x: x, [])
TypeError: reduce() of empty sequence with no initial value
Benefits:
Fails for multiple and zero values
Doesn't change the original list
Doesn't need a new variable and can be passed as an argument
Cons: "API misuse" (see comments).