Python: Modify tuple in list - python

My actual output looks like this:
target = [([('Kid', '200-5'), (u'Rock', '200-6')], u's725')]
How can I modify data in the tuple such that I can return, at the end, the modified list which has the same format as target?
For example: I'd like to change 'kid' in 'adult', such that the rest stays, i.e. I receive: newTarget = [([('adult', '200-5'), (u'Rock', '200-6')], u's725')]
My idea: Copy all the data of target in a temporary list, modify things and create the same format as in target.
BUT: How can I achieve this concretely?
Until now, I could Change and modify things, but I didn't get the same format again...

Have you tried this?
l = list(target[0][0][0])
l[0] = 'Adult'
target[0][0][0] = tuple(l)

Since tuples are immutable, you cannot modify their elements—you must replace them with new tuples. Lists are mutable, so you can replace individual parts as needed:
>>> x = [(1, 2), (3, 4), 5]
>>> x[0] = (x[0][0], 0)
>>> x
[(1, 0), (3, 4), 5]
In the above example, I create a list x containing tuples as its first and second elements and an int as its third. On the second line, I construct a new tuple to swap in to the first position of x, containing the first element of the old tuple, and a new element 0 to replace the 2.

You will need recursion if you need to be more flexible
target = [([('Kid', '200-5'), (u'Rock', '200-6')], u's725')]
def search_and_replace(inlist):
res = []
for t in inlist:
if isinstance(t, list):
res.append(search_and_replace(t))
elif isinstance(t, tuple):
t1, t2 = t
if t1 == 'Kid':
t1 = 'adult'
elif isinstance(t1, list):
t1 = search_and_replace(t1)
res.append((t1, t2))
else:
res.append(t)
return res
print search_and_replace(target)

Related

Convert tuple into index for nested list

I'm given coordinates for nested n-dimensional lists, in which I have to insert a certain value.
Something like (3,1,4) for a 3-D list or (3,1,4,1) for a 4-D list. The proper way to change this value would be:
mylist[3][1][4] = 'x'
mylist[3][1][4][1] = 'y'
It's easy to do this if I always know how many dimensions the list is, but I have to do this for any n. I'm also not allowed to import anything(lab assignment).Thanks!
This mylist[3][1][4][1] = thing is the same as this:
tmp = mylist[3][1][4]
tmp[1] = thing
You could use this fact like this:
def setitem(the_list, indices: tuple, value):
try:
index, = indices
except ValueError:
# there's more than one index - dig one dimension deeper
setitem(the_list[indices[0]], indices[1:], value)
else:
# one index left - use it in assignment
the_list[index] = value
Then call:
mylist[3][1][4][1] = 'y'
setitem(mylist, (3, 1, 4, 1), 'y')
An assignment like mylist[3][1][4] = 'x' is really a chain of method calls in disguise.
mylist.__getitem__(3).__getitem__(1).__setitem__(4, 'x')
As such, you'll need a loop; all but the last index in your tuple will
be used to get a reference to the list you are actually updating. The last index is used for the actual update.
idx = (3, 1, 4)
t = mylist
*dig, update = idx
for i in dig: # (3, 1) are used for __getitem__
t = t[i]
# t == mylist[3][1]
# t[4] = 'x' == t.__setitem__(4, 'x')
t[update] = 'x'
you could use a recursive approach:
def change_item(nested_list, indices, value):
if len(indices) > 1:
change_item(nested_list[indices[0]], indices[1:])
else:
nested_list[indices[0]] = value
change_item(mylist, (3,1,4), 'x')

When I append list of tuples to another list it becomes empty

When I try to add list of tuples to another list it becomes empty.
tagged_sentences_list = []
for i in range (len(sentences)):
length_sentences = len(sentences[i].split(" "))
del words_in_the_sentence[:]
del tagged_words[:]
for j in range (length_sentences):
length_words_in_sentence = len(sentences[i].split(" ")[j].split("/")[1:])
part_of_the_speech = sentences[i].split(" ")[j].split("/")[1:]
word = sentences[i].split(" ")[j].split("/")[:1]
words_in_the_sentence.append(word)
zipped = zip(word,part_of_the_speech)
tagged_words.append(zipped)
tagged_sentences_list.append(tagged_words)
Exactly in this line:
tagged_sentences_list.append(tagged_words)
Terminal prints
[[]]
I want to append lists of tuples to another list. So I would have:
[[(a,b),(c,d)], [(d,e)]]
Any of you have any idea why? Thanks
del tagged_words[:] empties the list, yes.
You have one list object that you keep filling and emptying, and you add references to another list. You are not creating copies here:
tagged_sentences_list.append(tagged_words)
Create new list objects:
tagged_sentences_list = []
for i in range (len(sentences)):
length_sentences = len(sentences[i].split(" "))
words_in_the_sentence = []
tagged_words = []
for j in range (length_sentences):
length_words_in_sentence = len(sentences[i].split(" ")[j].split("/")[1:])
part_of_the_speech = sentences[i].split(" ")[j].split("/")[1:]
word = sentences[i].split(" ")[j].split("/")[:1]
words_in_the_sentence.append(word)
zipped = zip(word,part_of_the_speech)
tagged_words.append(zipped)
tagged_sentences_list.append(tagged_words)
Python names are just references; you may want to read up on how Python's memory model works, I strongly recommend Ned Batchelder's Facts and myths about Python names and values.
Your code is doing a lot of redundant splitting too. Use the fact that Python for loops are for each constructs; there is no need to generate an index when you can just loop over the list itself:
tagged_sentences_list = []
for sentence in sentences:
tagged_words = []
for word in sentence.split(' '):
parts = word.split('/')[:2]
tagged_words.append(parts)
tagged_sentences_list.append(tagged_words)
Note that there is no need to use zip(); all you do is re-combine the first and second element of the / split result.
If you were to use list comprehensions, that could be further reduced to:
tagged_sentences_list = [
[word.split('/')[:2] for word in sentence.split(' ')]
for sentence in sentences]
Try this:
tagged_sentences_list.append(tagged_words[:])
Or...
import copy
tagged_sentences_list.append(copy.copy(tagged_words))
If you're on python3, you may also try
tagged_sentences_list.append(tagged_words.copy())
What your current code is doing is, appending the list to the bigger list, and then clearing it using del tagged_words[:].
Now, since the references are the same, you end up clearing the contents of what you stored inside the bigger list too.
Observe:
>>> x = []
>>> y = [(1, 2), (3, 4)]
>>> x.append(y)
>>> id(x[0])
4433923464
>>> id(y)
4433923464
>>> del y[:]
>>> x
[[]]
You've gotten an empty list because you appended and then cleared the original. Now, this is what happens when you make a copy of the list:
>>> x = []
>>> y = [(1, 2), (3, 4)]
>>> x.append(y[:])
>>> del y[:]
>>> x
[[(1, 2), (3, 4)]]

sorting a list numerically that has string and integar value

I am looking for a code that can sort a list say for example list x, which contains integers and string. the code would then sort the list x so that the integer value is sorted corresponding to the string. so far I have tried this code however it does not work.
x =["a" 2,"c" 10, "b" 5]
x.sort()
print (x)
I want the result to be
["a" 2 "b" 5 "C" 10]
so the list is sorted numerically in acceding order and the string is also printed.
Use List of Tuples and then sort them according to what you want, example:
x = [('b',5),('a',2),('c',10)]
x.sort() # This will sort them based on item[0] of each tuple
x.sort(key=lambda s: s[1]) # This will sort them based on item[1] of each tuple
Another approach is to use dictionary instead of list of tuples, example:
x = {'b':5,'a':2,'c':10}#This will be automatically sorted based on the key of each element
if you print x, you will get:
{'a': 2, 'c': 10, 'b': 5}
if you want to sort them based on the value of each element, then:
x = sorted(x.items(), key=lambda s:s[1])
This will create a new list of tuples, since sorted() returns "new" sorted list, hence the result will be:
[('a', 2), ('b', 5), ('c', 10)]
If I deducted correctly you also want the resulting list to have an integer where the original list has an integer (and the same for characters).
I don't think there is an out-of-the-box way to do that. One possible approach is to separate your list into two others: one with integer, one with chars. Then, after sorting each list, you can merge them respecting the desired positions of integers and chars.
Use a nested iterable to pair the letters to numbers, then sort the items by the second elements:
# just pairs.sort(key = lambda x: x[1])
pairs = [('a', 2), ('c', 10), ('b', 5)]
I considered the elements are separate. The following code might help, you can fill or remove the print statement in the except block, as you wish.
x =["a", 2,"c", 10, "b", 5]
numbers = []
letters = []
for element in x:
try:
numbers.append(int(element))
except:
letters.append(str(element))
numbers.sort()
letters.sort()
numbers.reverse()
letters.reverse()
for index,item in enumerate(x):
try:
print int(item),
x[index] = numbers.pop()
except ValueError:
x[index] = letters.pop()
print "\n"+ str(x)

How can I access each element of a pair in a pair list?

I have a list called pairs.
pairs = [("a", 1), ("b", 2), ("c", 3)]
And I can access elements as:
for x in pairs:
print x
which gives output like:
('a', 1) ('b', 2) ('c', 3)
But I want to access each element in each pair, like in c++, if we use pair<string, int>
we are able to access, first element and second element by x.first, and x.second.eg.
x = make_pair("a",1)
x.first= 'a'
x.second= 1
How can I do the same in python?
Use tuple unpacking:
>>> pairs = [("a", 1), ("b", 2), ("c", 3)]
>>> for a, b in pairs:
... print a, b
...
a 1
b 2
c 3
See also: Tuple unpacking in for loops.
If you want to use names, try a namedtuple:
from collections import namedtuple
Pair = namedtuple("Pair", ["first", "second"])
pairs = [Pair("a", 1), Pair("b", 2), Pair("c", 3)]
for pair in pairs:
print("First = {}, second = {}".format(pair.first, pair.second))
A 2-tuple is a pair. You can access the first and second elements like this:
x = ('a', 1) # make a pair
x[0] # access 'a'
x[1] # access 1
When you say pair[0], that gives you ("a", 1). The thing in parentheses is a tuple, which, like a list, is a type of collection. So you can access the first element of that thing by specifying [0] or [1] after its name. So all you have to do to get the first element of the first element of pair is say pair[0][0]. Or if you want the second element of the third element, it's pair[2][1].
I don't think that you'll like it but I made a pair port for python :)
using it is some how similar to c++
pair = Pair
pair.make_pair(value1, value2)
or
pair = Pair(value1, value2)
here's the source code
pair_stl_for_python
You can access the members by their index in the tuple.
lst = [(1,'on'),(2,'onn'),(3,'onnn'),(4,'onnnn'),(5,'onnnnn')]
def unFld(x):
for i in x:
print(i[0],' ',i[1])
print(unFld(lst))
Output :
1 on
2 onn
3 onnn
4 onnnn
5 onnnnn

Returning list elements and indices [duplicate]

This question already has answers here:
'Return' keyword returns only one element from a loop?
(3 answers)
Closed 8 years ago.
I am trying to print all the elements of a list using a user made function.
y = [1,2,3]
def ash(list1):
for x in range(len(list)):
return list[x],x
what i want to do is return all the values in the list with their indices,but all i get is a single element.I can get the elements to print but not return.
You are returning on the very first iteration. Rather, you need to create a list in your function, and add all the tuples in that list, and finally return that list.
And for getting both index and element, you can use enumerate():
def ash(list1):
new_list = []
for x, elem in enumerate(list1):
new_list.append((elem,x))
return new_list
Or, even better you can simply use List comprehension:
return [(elem, x) for x, elem in enumerate(list1)]
The previous two methods creates the list in memory. If you have a very large list to deal with, then you should probably use generators, using yield keyword:
def ash(list1):
for x, elem in enumerate(list1):
yield elem, x
Some issues with your code:
Don't iterate using range unless necessary. Iterate the list directly, or here, use enumerate
Don't use list as a variable - you'll shadow the built-in of the same name. It's confusing to the reader.
You're returning out of the loop. This is why you only get the first iteration. If you want to return successive values, use yield, which turns your function into a generator:
def ash(l):
for x in range(len(l)):
yield l[x],x
This is really a reimplementation of enumerate:
list(enumerate('abc')) #=> [(0, 'a'), (1, 'b'), (2, 'c')]
If you really want to swap the order of the pairs, you can do:
[b,a for a,b in enumerate('abc')]
Alternative implementation: l='abc';zip(l,xrange(len(l)))
enumerate(list) is what you're looking for. (see doc). Also, calling return will give you only the first value of the list when calling the function, what you want here is probably the yield statement:
def ash(list):
for i,item in enumerate(list):
yield item,i
if __name__ == '__main__':
y = [1,2,3]
ys_with_indices = list(ash(y))
print ys_with_indices
Note that this will return a generator object, which you have to convert to a list by calling list() on it. Alternatively, just use a normal list that you append the individual values to:
def ash(list):
items_with_indices = []
for i,item in enumerate(list):
items_with_indices.append((item,i))
return items_with_indices
if __name__ == '__main__':
y = [1,2,3]
ys_with_indices = ash(y)
print ys_with_indices
def ash(lst):
return [(lst[x],x) for x in range(0,len(lst))]
You will get a list of tuples where the first value of the tuple is an element of the original list and the second the index of the element in the list.
For y = [1,2,3] the result is [(1, 0), (2, 1), (3, 2)]

Categories