Convert tuple into index for nested list - python

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')

Related

Efficient way to add elements to a tuple

I want to add elements to a tuple. I found 2 ways to do it. This and this answers say add two tuples. It will create a new tuple
a = (1,2,3)
b = a + (5,)
Where as this says, convert the tuple to list, add the element and then convert it back to tuple
a = (1,2,3)
tmp = list(a)
tmp.insert(3, 'foobar')
b = tuple(tmp)
Which among these two is efficient in terms of memory and performance?
Also, suppose I want to insert an element in the middle of a tuple, is that possible using the first method?
Thanks!
If you are only adding a single element, use
a += (5, )
Or,
a = (*a, 5)
Tuples are immutable, so adding an element will mean you will need to create a new tuple object. I would not recommend casting to a list unless you are going to add many elements in a loop, or such.
a_list = list(a)
for elem in iterable:
result = process(elem)
a_list.append(result)
a = tuple(a_list)
If you want to insert an element in the middle, you can use:
m = len(a) // 2
a = (*a[:m], 5, *a[m:])
Or,
a = a[:m] + (5, ) + a[m:]

Compare 1 column of 2D array and remove duplicates Python

Say I have a 2D array like:
array = [['abc',2,3,],
['abc',2,3],
['bb',5,5],
['bb',4,6],
['sa',3,5],
['tt',2,1]]
I want to remove any rows where the first column duplicates
ie compare array[0] and return only:
removeDups = [['sa',3,5],
['tt',2,1]]
I think it should be something like:
(set first col as tmp variable, compare tmp with remaining and #set array as returned from compare)
for x in range(len(array)):
tmpCol = array[x][0]
del array[x]
removed = compare(array, tmpCol)
array = copy.deepcopy(removed)
print repr(len(removed)) #testing
where compare is:
(compare first col of each remaining array items with tmp, if match remove else return original array)
def compare(valid, tmpCol):
for x in range(len(valid)):
if valid[x][0] != tmpCol:
del valid[x]
return valid
else:
return valid
I keep getting 'index out of range' error. I've tried other ways of doing this, but I would really appreciate some help!
Similar to other answers, but using a dictionary instead of importing counter:
counts = {}
for elem in array:
# add 1 to counts for this string, creating new element at this key
# with initial value of 0 if needed
counts[elem[0]] = counts.get(elem[0], 0) + 1
new_array = []
for elem in array:
# check that there's only 1 instance of this element.
if counts[elem[0]] == 1:
new_array.append(elem)
One option you can try is create a counter for the first column of your array before hand and then filter the list based on the count value, i.e, keep the element only if the first element appears only once:
from collections import Counter
count = Counter(a[0] for a in array)
[a for a in array if count[a[0]] == 1]
# [['sa', 3, 5], ['tt', 2, 1]]
You can use a dictionary and count the occurrences of each key.
You can also use Counter from the library collections that actually does this.
Do as follows :
from collection import Counter
removed = []
for k, val1, val2 in array:
if Counter([k for k, _, _ in array])[k]==1:
removed.append([k, val1, val2])

Python: Modify tuple in list

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)

Python 2 dimensional table and distinct entries

I'm making a function called different(). It needs to take a two-dimensional table as input and return the number of distinct entries in the table. I'm not sure how to start it,m I would really appreciate some suggestions. When used, it should look like this in the shell:
t = [[1,0,1], [0,1,0]]
different(t)
>>2
This is what I have so far:
def different()-> int
''' takes a two-dimensional table and returns number of distinct entries'''
t = []
while
#use set method?
I think there are two possible interpretations
>>> set(j for i in t for j in i)
set([0, 1])
and
>>> set(tuple(i) for i in t) # equivalent to set(map(tuple, t))
set([(0, 1, 0), (1, 0, 1)])
Either way, different should return the len of the set
def different(t):
return len(set(...))
If you like itertools, you can do the following
from itertools import chain
def different(t):
return len(set(chain.from_iterable(t)))
def different(t):
return len(set(tuple(item) for item in t))
From basic knowledge of python you can solve the above problem
t = [[1,0,1], [0,1,0], [1,2,3], [1,0,1]]
a = []
for i in t:
if i not in a:
a.append(i)
print len(a)
you have created a new list name 'a' and you have inserted all those element in the list which are unique. And afetrwards you can get the length of the new list a.

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