I have the following code, and the idea is to be able to iterate over root for each string in some_list[j]. The goal is to stay away from nested for loops and learn a more pythonic way of doing this. I would like to return each value for the first item in some_list then repeat for the next item in some_list.
for i, value in enumerate(root.iter('{0}'.format(some_list[j])))
return value
Any ideas?
EDIT: root is
tree = ElementTree.parse(self._file)
root = tree.getroot()
I think what you're trying to do is this:
values = ('{0}'.format(root.iter(item)) for item in some_list)
for i, value in enumerate(values):
# ...
But really, '{0}'.format(foo) is silly; it's just going to do the same thing as str(foo) but more slowly and harder to understand. Most likely you already have strings, so all you really need is:
values = (root.iter(item) for item in some_list)
for i, value in enumerate(values):
# ...
You could merge those into a single line, or replace the genexpr with map(root.iter, some_list), etc., but that's the basic idea.
At any rate, there are no nested loops here. There are two loops, but they're just interleaving—you're still only running the inner code once for each item in some_list.
So, given List A, which contains multiple lists, you want to return the first element of each list? I may not be understanding you correctly, but if so you can use a list comprehension...very "Pythonic" ;)
In [1]: some_list = [[1,2,3],[4,5,6],[7,8,9]]
In [2]: new = [x[0] for x in some_list]
In [3]: new
Out[3]: [1, 4, 7]
You could try using chain()
from the itertools module. It would look something like
from itertools import chain
all_items = chain(*[root.iter('{0}'.format(x) for x in some_list)])
for i, value in enumerate(all_items):
return value # or yield i, value, or whatever you need to do with value
Related
I know how to create a new list based on the values of an existing list, eg casting
numspec = [float(x) for x in textspec]
Now I have a list of numbers where I need to subtract a value based on the index of a list. I have calculated an a and b value and ended up doing
peakadj = []
for i in range(len(peakvalues)):
val=peakvalues[i]-(i*a+b)
peakadj.append(val)
This works, but I don't like the feel of it, is there any more pythonic way of doing this?
Use the builtin enumerate function and a list comprehension.
peakadj = [val-(i*a+b) for i, val in enumerate(peakvalues)]
Perhaps faster:
from itertools import count
peakadj = [val-iab for val, iab in zip(peakvalues, count(b, a))]
Or:
from itertools import count
from operator import sub
peakadj = [*map(sub, peakvalues, count(b, a))]
Little benchmark
Given a list of integers, I want to check a second list and remove from the first only those which can not be made from the sum of two numbers from the second. So given a = [3,19,20] and b = [1,2,17], I'd want [3,19].
Seems like a a cinch with two nested loops - except that I've gotten stuck with break and continue commands.
Here's what I have:
def myFunction(list_a, list_b):
for i in list_a:
for a in list_b:
for b in list_b:
if a + b == i:
break
else:
continue
break
else:
continue
list_a.remove(i)
return list_a
I know what I need to do, just the syntax seems unnecessarily confusing. Can someone show me an easier way? TIA!
You can do like this,
In [13]: from itertools import combinations
In [15]: [item for item in a if item in [sum(i) for i in combinations(b,2)]]
Out[15]: [3, 19]
combinations will give all possible combinations in b and get the list of sum. And just check the value is present in a
Edit
If you don't want to use the itertools wrote a function for it. Like this,
def comb(s):
for i, v1 in enumerate(s):
for j in range(i+1, len(s)):
yield [v1, s[j]]
result = [item for item in a if item in [sum(i) for i in comb(b)]]
Comments on code:
It's very dangerous to delete elements from a list while iterating over it. Perhaps you could append items you want to keep to a new list, and return that.
Your current algorithm is O(nm^2), where n is the size of list_a, and m is the size of list_b. This is pretty inefficient, but a good start to the problem.
Thee's also a lot of unnecessary continue and break statements, which can lead to complicated code that is hard to debug.
You also put everything into one function. If you split up each task into different functions, such as dedicating one function to finding pairs, and one for checking each item in list_a against list_b. This is a way of splitting problems into smaller problems, and using them to solve the bigger problem.
Overall I think your function is doing too much, and the logic could be condensed into much simpler code by breaking down the problem.
Another approach:
Since I found this task interesting, I decided to try it myself. My outlined approach is illustrated below.
1. You can first check if a list has a pair of a given sum in O(n) time using hashing:
def check_pairs(lst, sums):
lookup = set()
for x in lst:
current = sums - x
if current in lookup:
return True
lookup.add(x)
return False
2. Then you could use this function to check if any any pair in list_b is equal to the sum of numbers iterated in list_a:
def remove_first_sum(list_a, list_b):
new_list_a = []
for x in list_a:
check = check_pairs(list_b, x)
if check:
new_list_a.append(x)
return new_list_a
Which keeps numbers in list_a that contribute to a sum of two numbers in list_b.
3. The above can also be written with a list comprehension:
def remove_first_sum(list_a, list_b):
return [x for x in list_a if check_pairs(list_b, x)]
Both of which works as follows:
>>> remove_first_sum([3,19,20], [1,2,17])
[3, 19]
>>> remove_first_sum([3,19,20,18], [1,2,17])
[3, 19, 18]
>>> remove_first_sum([1,2,5,6],[2,3,4])
[5, 6]
Note: Overall the algorithm above is O(n) time complexity, which doesn't require anything too complicated. However, this also leads to O(n) extra auxiliary space, because a set is kept to record what items have been seen.
You can do it by first creating all possible sum combinations, then filtering out elements which don't belong to that combination list
Define the input lists
>>> a = [3,19,20]
>>> b = [1,2,17]
Next we will define all possible combinations of sum of two elements
>>> y = [i+j for k,j in enumerate(b) for i in b[k+1:]]
Next we will apply a function to every element of list a and check if it is present in above calculated list. map function can be use with an if/else clause. map will yield None in case of else clause is successful. To cater for this we can filter the list to remove None values
>>> list(filter(None, map(lambda x: x if x in y else None,a)))
The above operation will output:
>>> [3,19]
You can also write a one-line by combining all these lines into one, but I don't recommend this.
you can try something like that:
a = [3,19,20]
b= [1,2,17,5]
n_m_s=[]
data=[n_m_s.append(i+j) for i in b for j in b if i+j in a]
print(set(n_m_s))
print("after remove")
final_data=[]
for j,i in enumerate(a):
if i not in n_m_s:
final_data.append(i)
print(final_data)
output:
{19, 3}
after remove
[20]
I have a list populated from entries of a log; for sake of simplicity, something like
listlog = ["entry1:abcde", "entry2:abbds", "entry1:eorieo", "entry3:orieqor", "entry2:iroewiow"......]
This list can have an undefined number of entry, which may or may not be in sequence, since I run multiple operations in async fashion.
Then I have another list, which I use as reference to get only the list of entries; which may be like
list_template = ["entry1", "entry2", "entry3"]
I am trying to use the second list, to get sequences of entries, so I can isolate the single sequence, taking only the first instance found of each entry.
Since I am not dealing with numbers, I can't use set, so I did try with a loop inside a loop, comparing values in each list
This does not work, because it is possible that another entry may happen before what I am looking for (say, I want entry1, entry2, entry3, and the loop find entry1, but then find entry3, and since I compare every element of each list, it will be happy to find an element)
for item in listlog:
entry, value = item.split(":")
for reference_entry in list_template:
if entry == reference_entry:
print item
break
I have to, in a nutshell, find a sequence as in the template list, while these items are not necessarily in order. I am trying to parse the list once, otherwise I could do a very expensive multi-pass for each element of the template list, until I find the first occurrence and bail out. I thought that doing the loop in the loop is more efficient, since my reference list is always smaller than the log list, which is usually few elements.
How would you approach this problem, in the most efficient and pythonic way? All that I can think of, is multiple passes on the log list
you can use dict:
>>> listlog
['entry1:abcde', 'entry2:abbds', 'entry1:eorieo', 'entry3:orieqor', 'entry2:iroewiow']
>>> list_template
['entry1', 'entry2', 'entry3']
>>> for x in listlog:
... key, value = x.split(":")
... if key not in my_dict and key in list_template:
... my_dict[key] = value
...
>>> my_dict
{'entry2': 'abbds', 'entry3': 'orieqor', 'entry1': 'abcde'}
Disclaimer : This answer could use someone's insight on performance. Sure, list/dict comprehensions and zip are pythonic but the following may very well be a poor use of those tools.
You could use zip :
>>> data = ["a:12", "b:32", "c:54"]
>>> ref = ['c', 'b']
>>> matches = zip(ref, [val for key,val in [item.split(':') for item in data] if key in ref])
>>> for k, v in matches:
>>> print("{}:{}".format(k, v))
c:32
b:54
Here's another (worse? I'm not sure, performance-wise) way to get around this :
>>> data = ["a:12", "b:32", "c:54"]
>>> data_dict = {x:y for x,y in [item.split(':') for item in data]}
>>> ["{}:{}".format(key, val) for key,val in md.items() if key in ref]
['b:32', 'c:54']
Explanation :
Convert your initial list into a dict using a dict
For each pair of (key, val) found in the dict, join both in a string if the key is found in the 'ref' list
You can use a list comprehension something like this:
import re
listlog = ["entry1:abcde", "entry2:abbds", "entry1:eorieo", "entry3:orieqor", "entry2:iroewiow"]
print([item for item in listlog if re.search('entry', item)])
# ['entry1:abcde', 'entry2:abbds', 'entry1:eorieo', 'entry3:orieqor', 'entry2:iroewiow']
Than u can split 'em as u wish and create a dictonary if u want:
import re
listlog = ["entry1:abcde", "entry2:abbds", "entry1:eorieo", "entry3:orieqor", "entry2:iroewiow"]
mylist = [item for item in listlog if re.search('entry', item)]
def create_dict(string, dict_splitter=':'):
_dict = {}
temp = string.split(dict_splitter)
key = temp[0]
value = temp[1]
_dict[key] = value
return _dict
mydictionary = {}
for x in mylist:
x = str(x)
mydictionary.update(create_dict(x))
for k, v in mydictionary.items():
print(k, v)
# entry1 eorieo
# entry2 iroewiow
# entry3 orieqor
As you see this method need an update, cause we have changing the dictionary value. That's bad. Most better to update value for the same key. But it's much easier as u can think
I am supposed to do the following:
Define a function my_enumerate(items) that behaves in a similar way to the built-in enumerate function. It should return a list of pairs (i, item) where item is the ith item, with 0 origin, of the list items (see the examples below). Check the test cases for how the function should work. Your function must not call Python's in-built enumerate function.
Examples:
Input:
ans = my_enumerate([10, 20, 30])
print(ans)
Output:
[(0, 10), (1, 20), (2, 30)]
What does enumerate do? Try expressing it in English, and it may help you understand how to write the necessary code. If it doesn't then the practice of learning English language descriptions into code will be useful.
One way of describing enumerate is to say it iterates over each item in the list, and for each item in the input list it produces a pair of the item's index in the input list and the item.
So we know we need to iterate over the list:
for item in input_list:
pass
And we need to keep track of the index of the current item.:
index = 0
for item in input_list:
index += 1
Hmm, there's a better way of doing that:
for index in range(len(input_list)):
pass
Now to produce the pairs:
for index in range(len(input_list)):
pair = index, input_list[index]
You also need somewhere to store these pairs:
def my_enumerate(input_list):
output_list = []
for index in range(len(input_list)):
pair = index, input_list[index]
output_list.append(pair)
return output_list
Are there other ways to write code that produces the same output? Yes. Is this the best way to write this function? Not by a long shot. What this exercise should help you with is turning your thoughts into code, as you gain more experience doing that then you can combine multiple steps at a time, and start using more complicated programming concepts.
Use itertools.count and zip:
from itertools import count
def my_enumerate(values):
return list(zip(count(), values))
I have a little code that takes a list of objects, and only outputs the items in the list that are unique.
This is my code
def only_once(a):
return [x for x in a if a.count(x) is 1]
My teacher requires us to use sets for this function though.
Can someone show me what I can do?
My code has to take an input such as a=[1,4,6,7,3,2,4,5,7,5,6], and output [1, 3, 2]. Has to retain it's order also.
[I'm assuming that you're also user1744238 and user1744316 -- please pick a username and stick to it, that way it's easier to check to see what variants of a question you've asked and what you've already tried.]
One set-based approach is to use two sets as a counter. You only care about whether you've seen something once or more than once. For example, here's an easy-to-explain approach:
Make an empty set for once and more.
Loop over every element of your list, and:
If you haven't seen it before, add it to once.
If you've seen it once, remove it from once and add it to more.
Now you know what elements you've seen exactly once, in the set once.
Loop over the elements of the list, and if you've seen it once, add it to the output list, and remove it from the once set so you don't output the same element twice.
This gives me:
In [49]: f([1,4,6,7,3,2,4,5,7,5,6])
Out[49]: [1, 3, 2]
To clarify, what you want is a set of items that appear once, and only once.
The best option here is to use collections.Counter(), as it means you only count the items once, rather than once per item, greatly increasing performance:
>>> import collections
>>> {key for key, count in collections.Counter(a).items() if count == 1}
{1, 2, 3}
We simply replace the square brackets with curly braces to signify a set comprehension over a list comprehension, to get a set of results.
If you need to remove any item that is in the list more than once, not just occurences after the first, you can use:
# without using generators / comprehensions
def only_once(iterable):
seen = set()
duplicates = set()
for item in iterable:
if item in seen:
duplicates.add(item)
seen.add(item)
result = []
for item in iterable:
if item not in duplicates:
result.append(item)
return result
For general order-preserving duplicate elimination, see unique_everseen in the itertools recipes:
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
# unique_everseen('ABBCcAD', str.lower) --> A B C D
seen = set()
seen_add = seen.add
if key is None:
for element in ifilterfalse(seen.__contains__, iterable):
seen_add(element)
yield element
else:
for element in iterable:
k = key(element)
if k not in seen:
seen_add(k)
yield element