I believe I've made an error in my coding in where my list of tuples prints out vertically instead of the correct way. May someone please tell me what's up?
This is the question being asked:
Enumerate It!
Write a function called enum that takes a sequence and returns a list of 2-tuples with each tuple holding the index and its associated item.
This is the example given:
>>> enum([45,67,23,34,88,12,90])
[(0, 45), (1, 67), (2, 23), (3, 34), (4, 88), (5, 12), (6, 90)]
>> enum('hello')
[(0, 'h'), (1, 'e'), (2, 'l'), (3, 'l'), (4, 'o')]
This is my code:
def enum(aSequence):
for i in range(7):
b=aSequence[i]
a= [i]
list1 = [a,b]
print (list1)
If following the example input is used this is the result:
[[0], 45]
[[1], 67]
[[2], 23]
[[3], 34]
[[4], 88]
[[5], 12]
[[6], 90]
The result I would desire is:
[(0, 45), (1, 67), (2, 23), (3, 34), (4, 88), (5, 12), (6, 90)]
When I take away print(list1) and use return list1 instead this is the result.
[[0], 13]
Why is this the case?
When I put this into the website in which I'm being tutored on, the word "Jack and Jane" is displayed and random numbers are shown if a different test. My second question is how do I get the range loop to fit based on the parameter input. I tried to import math and import random. While both are short term solutions they aren't long term solutions.
I feel like I'm overthinking the problem as the code is there just the basic fundamentals might be missing.
The question asks you to return a list with the desired structure, so be careful about that. You are just printing one right now.
def enum(aSequence):
list1 = []
for i in range(len(aSequence)):
b = aSequence[i]
a = i
# use append to keep your items in the list to be returned
list1.append((a, b))
return list1
print(enum('hello')) # this should print horizontally like you asked.
Regarding the simplest answer to create the list you want, the enumerate function is your friend. The enumerate function unpacks a tuple of the index and the object found at the index for an iterable.
thing = 'hello there!'
#typical use case for enumerate
for i, item in enumerate(thing):
print(i, item)
So here's an example function that does what you want...
def enum(iterable):
# must use list() to cast it as an object or else we return a generator object
return list(enumerate(iterable))
enum('hello there!')
You are almost correct. The problem is with your a=[i]. By using [] brackets you are creating a list, so a is a list, instead of an int.
Change a=i and it will be fine. Also hardcoded range(7) should be changed to range(len(aSequence)). The ideal solution for you would be something like:
def enum(aSequence):
result = []
for i in range(len(aSequence)):
result.append((i, aSequence[i]))
return result
What you need to remember is the fact, that print is not a return.
This is how it should be. You need to create the list before starting the loop.Just like below
def enum(aSequence):
list1 = []
for i in range(len(aSequence)):
b = aSequence[i]
a = i
list1.append((a,b))
print list1
enum([45,67,23,34,88,12,90])
This is what you need to print everything in the same line
for i in range(len(aSequence)):
b=aSequence[i]
a= i
list1 = [a,b]
print (list1,end=' ')
Since you wanted the result
[(0, 45), (1, 67), (2, 23), (3, 34), (4, 88), (5, 12), (6, 90)]
Related
all I have a list of list of tuple here
A =[[(1, 52), (1, 12), (-1, -1)],[(-1, 23), (1, 42), (-1, -1)],[(1, -1), (-1, -1), (1, 42)]]
I wanted get the tuples containing the max values in second element of the tuple, column-wise.
I tried accessing columns like this
A[:,2]
But I get the error
TypeError: list indices must be integers, not tuple
Thanks in advance, Please let me know if you need any other information
Edit 1:
Desired output:
[(1, 52),(1, 42),(1, 42)]
[max(a,key=lambda x:x[1]) for a in zip(*A)]
output:
[(1, 52), (1, 42), (1, 42)]
Let me know if this works for you I will explain the answer.
You can access columns like this..
>>> list(zip(*A)[0])
[(1, 52), (-1, 23), (1, -1)]
>>> list(zip(*A)[1])
[(1, 12), (1, 42), (-1, -1)]
Explanation
zip https://docs.python.org/3/library/functions.html#zip
>>> x=[1,2,3]
>>> y=['a','b','c']
>>> z=['first','second','third']
>>> zip(x,y,z)
[(1, 'a', 'first'), (2, 'b', 'second'), (3, 'c', 'third')]
Now imagine x,y,z being the rows you had in A. By zip(rows) it returns 1st elements, 2nd elements, 3rd elements etc... There by returning us columns of the rows we passed.
Note: zip acts on multiple arguments passed in so we need to send multiple rows like x,y,z separately, not like [x,y,z] as a list. That is done by *A which separates the rows and passes to zip.
Now we got different columns
maxhttps://docs.python.org/3/library/functions.html#max
max(1,2) #Will return 2
max(cars,lambda x:x.speed) #Will give you the fastest car
max(cars,lambda x:x.capacity) #Will give you the biggest passenger car
max(tups,lambda x:x[1]) #Will give you the tuple with biggest 2nd element
List Comprehensionhttps://docs.python.org/3/tutorial/datastructures.html#list-comprehensions
A=[1,2,3]
[x**2 for x in A] #Will give you [1,4,9]
[x**3 for x in A] #Will give you [1,8,27]
Finally
[max(a,key=lambda x:x[1]) for a in zip(*A)]
Will give you max for each column!
You can try this:
A =[[(1, 52), (1, 12), (-1, -1)],[(-1, 23), (1, 42), (-1, -1)],[(1, -1), (-1, -1), (1, 42)]]
new_A = [max(a, key=lambda x: x[-1]) for a in zip(*A)]
Output:
[(1, 52), (1, 42), (1, 42)]
A is a list is lists of tuples. Basic Python does not recognised multiple-element subscripting, although Numpy and similar modules extend it. Your subscript expression :,2 is therefore interpreted as a tuple whose first element is a lice and whose second element is an integer, which (as the message explains) is not acceptable as a list index.
Unfortunately, "the tuples containing the max values in second element of the tuple, column-wise" isn't a terribly good description of the actual desired result.
I presume the answer you would like is [(1, 52), (1, 42), (1, 42)].
One relatively simple way to achieve this is to sort each of the sub-lists separately, taking the last element of each. this could be spelled as
result = [sorted(x, key=lambda z: z[1])[-1] for x in A]
The key argument to the sorted function ensures that each list is sorted on its second element, the
[-1] subscript takes the last (and therefore highest) element of the sorted list, and the for x in A ensure that each element of the output corresponds to an element (i.e., a list of three tuples) of the input.
I am a newbie to python. Trying to learn how to access Lists inside a Tuple inside a List. My List is:
holidays = [(0,),
(1, [2, 16]),
(2, [20]),
(4, [14]),
(5, [29]),
(7, [4]),
(9, [4]),
(11, [23, 24]),
(12, [25])]
I would like to know the best way to access each tuple and its list in a more efficient way. I tried using:
for i, tuples in enumerate(holidays):
for list in tuples:
print list
But i get the following error:
for list in tuples:
TypeError: 'int' object is not iterable
Help would be much appreciated.
You need to remove the i in the first for loop:
for tuples in enumerate(holidays):
for list in tuples:
print list
short version
[y for x in holidays if isinstance(x, tuple) for y in x if isinstance(y, list)]
You can't do a for .. in LOOP on an integer, that's why the program cras
Well, your holidays list is not uniform: the first entry is an integer (0), the others are tuples.
holidays = [0, # <- integer
(1, [2, 16]),
(2, [20]),
(4, [14]),
(5, [29]),
(7, [4]),
(9, [4]),
(11, [23, 24]),
(12, [25])]
Here is a possible loop:
for entry in holidays:
if entry == 0:
continue # don't know what to do with zero
month, days = entry
print(month, days)
We use unpaking to extract the month and the days.
See Tuples and Sequences in the Python tutorial.
Change your first element 0 to (0), Also, remove 'i' from your for loop, as told by Stavros, it will work.
holidays = [([0]),
(1, [2, 16]),
(2, [20]),
(4, [14]),
(5, [29]),
(7, [4]),
(9, [4]),
(11, [23, 24]),
(12, [25])]
tuples in enumerate(holidays):
list in tuples:
print list
I'm trying to add a new tuple to a list of tuples (sorted by first element in tuple), where the new tuple contains elements from both the previous and the next element in the list.
Example:
oldList = [(3, 10), (4, 7), (5,5)]
newList = [(3, 10), (4, 10), (4, 7), (5, 7), (5, 5)]
(4,10) was constructed from and added in between (3,10) and (4,7).
Construct (x,y) from (a,y) and (x,b)
I've tried using enumerate() to insert at the specific position, but that doesn't really let me access the next element.
oldList = [(3, 10), (4, 7), (5,5)]
def pair(lst):
# create two iterators
it1, it2 = iter(lst), iter(lst)
# move second to the second tuple
next(it2)
for ele in it1:
# yield original
yield ele
# yield first ele from next and first from current
yield (next(it2)[0], ele[1])
Which will give you:
In [3]: oldList = [(3, 10), (4, 7), (5, 5)]
In [4]: list(pair(oldList))
Out[4]: [(3, 10), (4, 10), (4, 7), (5, 7), (5, 5)]
Obviously we need to do some error handling to handle different possible situations.
You could also do it using a single iterator if you prefer:
def pair(lst):
it = iter(lst)
prev = next(it)
for ele in it:
yield prev
yield (prev[0], ele[1])
prev = ele
yield (prev[0], ele[1])
You can use itertools.tee in place of calling iter:
from itertools import tee
def pair(lst):
# create two iterators
it1, it2 = tee(lst)
# move second to the second tuple
next(it2)
for ele in it1:
# yield original
yield ele
# yield first ele from next and first from current
yield (next(it2)[0], ele[1])
You can use a list comprehension and itertools.chain():
>>> list(chain.from_iterable([((i, j), (x, j)) for (i, j), (x, y) in zip(oldList, oldList[1:])])) + oldList[-1:]
[(3, 10), (4, 10), (4, 7), (5, 7), (5, 5)]
Not being a big fan of one-liners (or complexity) myself, I will propose a very explicit and readable (which is usually a good thing!) solution to your problem.
So, in a very simplistic approach, you could do this:
def insertElements(oldList):
"""
Return a new list, alternating oldList tuples with
new tuples in the form (oldList[i+1][0],oldList[i][1])
"""
newList = []
for i in range(len(oldList)-1):
# take one tuple as is
newList.append(oldList[i])
# then add a new one with items from current and next tuple
newList.append((oldList[i+1][0],oldList[i][1]))
else:
# don't forget the last tuple
newList.append(oldList[-1])
return newList
oldList = [(3, 10), (4, 7), (5, 5)]
newList = insertElements(oldList)
That will give you the desired result in newList:
print(newList)
[(3, 10), (4, 10), (4, 7), (5, 7), (5, 5)]
This is not much longer code than other more sophisticated (and memory efficient!) solutions, like using generators, AND I consider it a lot easier to read than intricate one-liners. Also, it would be easy to add some checks to this simple function (like making sure you have a list of tuples).
Unless you already know you need to optimize this particular piece of your code (assuming this is part of a bigger project), this should be good enough. At the same time it is: easy to implement, easy to read, easy to explain, easy to maintain, easy to extend, easy to refactor, etc.
Note: all other previous answers to your question are also better solutions than this simple one, in many ways. Just wanted to give you another choice. Hope this helps.
I have a list of pairs of numbers with the list sorted by the number on the right- eg:
[(7, 1)
(6, 2)
(5, 3)
(8, 5)
(9, 7)
(4, 9)]
and I want to get out the strands that are linked. A strand is defined as:
x->y->z
where tuples exist:
(y, x)
(z, y)
The strands in the above example are:
1->7->9->4
2->6
3->5->8
in the above example. I cannot think of any sensible code; as simple iteration with a counting variable will cause significant repeats. Please give me some pointers.
There's an easier way to do this than a real linked list. Since there's no real need for traversal, you can simply build regular lists as you go.
ts = [(7, 1),
(6, 2),
(5, 3),
(8, 5),
(9, 7),
(4, 9)]
def get_strands(tuples):
'''builds a list of lists of connected x,y tuples
get_strands([(2,1), (3,2), (4,3)]) -> [[1,2,3,4]]
Note that this will not handle forked or merging lists intelligently
'''
lst = []
for end, start in tuples:
strand = next((strand for strand in lst if strand[-1]==start), None)
# give me the sublist that ends with `start`, or None
if strand is None:
lst.append([start, end]) # start a new strand
else:
strand.append(end)
return lst
Demo:
In [21]: get_strands(ts)
Out[21]: [[1, 7, 9, 4], [2, 6], [3, 5, 8]]
I think the most complete solution is to create a graph from your data and then perform a topological sort on it. It will provide your expected result as long as the your graph doesn't have any cycles.
I have a list of lists of tuples
A= [ [(1,2,3),(4,5,6)], [(7,8,9),(8,7,6),(5,4,3)],[(2,1,0),(1,3,5)] ]
The outer list can have any number of inner lists, the inner lists can have any number of tuples, a tuple always has 3 integers.
I want to generate all combination of tuples, one from each list:
[(1,2,3),(7,8,9),(2,1,0)]
[(1,2,3),(7,8,9),(1,3,5)]
[(1,2,3),(8,7,6),(2,1,0)]
...
[(4,5,6),(5,4,3),(1,3,5)]
A simple way to do it is to use a function similar to itertools.poduct()
but it must be called like this
itertools.product([(1,2,3),(4,5,6)], [(7,8,9),(8,7,6),(5,4,3)],[(2,1,0),(1,3,5)])
i.e the outer list is removed. And I don't know how to do that. Is there a better way to generate all combinations of tuples?
itertools.product(*A)
For more details check the python tutorial
This works for your example, if there is only one level of nested lists (no lists of lists of lists):
itertools.product(*A)
you can probably call itertools.product like so:
itertools.product(*A) # where A is your list of lists of tuples
This way it expands your list's elements into arguments for the function you are calling.
Late to the party but ...
I'm new to python and come from a lisp background. This is what I came up with (check out the var names for lulz):
def flatten(lst):
if lst:
car,*cdr=lst
if isinstance(car,(list)):
if cdr: return flatten(car) + flatten(cdr)
return flatten(car)
if cdr: return [car] + flatten(cdr)
return [car]
Seems to work. Test:
A = [ [(1,2,3),(4,5,6)], [(7,8,9),(8,7,6),(5,4,3)],[(2,1,0),(1,3,5)] ]
flatten(A)
Result:
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (8, 7, 6), (5, 4, 3), (2, 1, 0), (1, 3, 5)]
Note: the line car,*cdr=lst only works in Python 3.0
This is not exactly one step, but this would do what you want if for some reason you don't want to use the itertools solution:
def crossprod(listoflists):
if len(listoflists) == 1:
return listoflists
else:
result = []
remaining_product = prod(listoflists[1:])
for outertupe in listoflists[0]:
for innercombo in remaining_product[0]:
newcombo = [outertupe]
newcombo.append(innercombo)
result.append(newcombo)
return result
def flatten(A)
answer = []
for i in A:
if type(i) == list:
ans.extend(i)
else:
ans.append(i)
return ans
This may also be achieved using list comprehension.
In [62]: A = [ [(1,2,3),(4,5,6)], [(7,8,9),(8,7,6),(5,4,3)],[(2,1,0),(1,3,5)] ]
In [63]: improved_list = [num for elem in A for num in elem]
In [64]: improved_list
Out[64]: [(1, 2, 3), (4, 5, 6), (7, 8, 9), (8, 7, 6), (5, 4, 3), (2, 1, 0), (1, 3, 5)]