How to manipulate a tuple that contains multiple tuple - python

For example, I have this tuple:
data =(('name/score','game1', 'game2', 'game3', 'game4', 'game5'),('A','1','2','3','4','5'),('B','6','7','8','9','10'),('C','11','12','13','14','15'))
so data is a tuple that contains 4 smaller tuples that contains strings.
Actually data is a 'table' which shows the name A, B, C and D and their respective scores.
How to manipulate data, so that I extra informations I want in data?
For example,
1. how to split data into smaller tuples such as
tuple1 = ('name/score','game1', 'game2', 'game3', 'game4', 'game5')
tuple2 = ('A','1','2','3','4','5')
and so on?
How to remove the 'names', which are A, B and C in each smaller tuple?
I did it by slicing:
newtuple = tuple1[1:]
Just wondering if there is a recursive way or iterative way to do it, cause I dont really get the idea of iteration and recursion.
Is there anyway to define a function which can retrieve the data I want?
for example, I want to know to score of A in game 3, the function should return "3".

data =(('name/score','game1', 'game2', 'game3', 'game4', 'game5'),('A','1','2','3','4','5'),('B','6','7','8','9','10'),('C','11','12','13','14','15'))
The first element of your tuple is a sort of header (like in an excel file the first line).
You want to construct a dictionary of dictionaries where the first level keys are the users (A, B, C, etc.) and the second level of dictionaries have keys like game1, game2, etc. with the value representing the score reached in the given game.
D = dict((t[0], dict(zip(data[0][1:], t[1:]))) for t in data[1:])
dict(zip(data[0][1:], t[1:])) is the part where you create a dictionary from every tuple of data (starting the second tuple) as values using keys from the first tuple of data ("game1", "game2", etc.). We deliberately ignore the very first element of all tuples: "name/score" is ignored, and the user names "A", "B", etc. are also ignored.
Then we "attach" to each dictionary obtained above to a key which is the username: (t[0], dict(zip.... and we obtain a tuple.
Finally from the list of tuples we create a dictionary using the dict builtin function.
The above code will convert your input tuple of tuples to a dictionary of dictionaries like:
{'A': {'game1': '1', 'game2': '2', 'game3': '3', 'game4': '4', 'game5': '5'},
'B': {'game1': '6', 'game2': '7', 'game3': '8', 'game4': '9', 'game5': '10'},
'C': {'game1': '11', 'game2': '12', 'game3': '13', 'game4': '14', 'game5': '15'}}
To get the score of user A in game3 you write:
>>D["A"]["game3"]
3
Since you commented that you don't want to use dictionaries, here is a function that should satisfy your needs:
def get_score(D, user, game):
i = D[0].index(game)
for t in D[1:]:
if t[0] == user:
return t[i]
print get_score(data, "A", "game3")

Related

Repeat items in list and maintain order of occurrence until maximum length of list is reached

I have a list of values in a list. The length of the list is variable from 1-5. If the list is less than the maximum_length then the list should be expanded, but should never exceed the max length.
I want to expand the list incrementally to distribute the items across the list starting from the first item. Below is the input list and the desired output. The amount of items duplicated is correct, but the order is not.
This list can be string values, so simply sorting the list is not a solution.
Example 1
current_list: ['#f8f8f8']
result: ['#f8f8f8', '#f8f8f8', '#f8f8f8', '#f8f8f8', '#f8f8f8']
desired result: ['#f8f8f8', '#f8f8f8', '#f8f8f8', '#f8f8f8', '#f8f8f8']
Example 2
current_list: ['#090909', '#171717']
result: ['#090909', '#171717', '#090909', '#171717', '#090909']
desired result: ['#090909', '#090909', '#090909', '#171717', '#171717']
Example 3
current_list: ['#d8d8d8', '#ececec', '#f1f1f1']
result: ['#d8d8d8', '#ececec', '#f1f1f1', '#d8d8d8', '#ececec']
desired result: ['#d8d8d8', '#d8d8d8', '#ececec', '#ececec', '#f1f1f1']
Example 4
current_list: ['#ecede7', '#eff0eb', '#f1f2ed', '#ffffff']
result: ['#ecede7', '#eff0eb', '#f1f2ed', '#ffffff', '#ecede7']
desired result: ['#ecede7', '#ecede7', '#eff0eb', '#f1f2ed', '#ffffff']
Below is my code to produce the list. How can I update this to get the desired output?
print([current_list * max_len][0][:max_len])
Updated to show that using sort isn't what I need. The purpose of this question is to maintain the distribution of the original list.
Use sort as explained in the comments and to maintain the distribution of the original list, the sort key should be the index of the element in your original list.
max_len = 5
current_list = ['1','2','3','4']
inter = [current_list * max_len][0][:max_len] # assume we stick with your function
# ['1', '2', '3', '4', '1']
sorted(inter, key=current_list.index)
# ['1', '1', '2', '3', '4']
Works with any order, sorts on the original order.
current_list = ['2','3','4', '1']
inter = [current_list * max_len][0][:max_len]
sorted(inter, key=current_list.index)
# ['2', '2', '3', '4', '1']
If your list is larger, you can use a more efficient key for the sort, like a dictionary which stores the elements and keys and their index as values.
Here are some other answers discussing sorting like this.

Array pagination unknown failure

I was resolving a HackerRank quiz, which consisted in emulating a pagination request.
The function received an array of items, the sort parameter, the sort order, the page number, and the items per page, and returns an array of names corresponding to the given page.
The items had the shape [name: string, relevance: int, price: int].
The sort parameter was 0 for name, 1 for relevance, and 2 for price.
The sort order was 0 for ascending and 1 for descending.
I tried the function in JavaScript and in Python, in case the default sorting function worked different and altered the results. This is my implementation in Python3.
def fetchPaginated(items, sortParameter, sortOrder, pageNum, itemsPerPage):
sortedItems = sorted(items, key=lambda item: item[sortParameter], reverse=False if sortOrder == 0 else True)
paginatedIdx = pageNum * itemsPerPage
slicedItems = sortedItems[paginatedIdx:(paginatedIdx + itemsPerPage)]
return map(lambda item: item[0], slicedItems)
Since HackerRank has hidden test cases, I don't know the inputs for the failing tests. I remember that the size of the array was in the order of the 100s and 1000s, the page number was between 0 and 2, the items per page between 1 and 20. There wasn't a pattern for the sort parameter and order (it wasn't like all the failing tests were for the sort parameter 1 or similar).
Could someone indicate me if my code, or the algorithm behind it has a flaw I don't detect? Maybe a flaw that makes it fail on edge cases?
EDIT:
Link to the HackerRank question. I don't know if it's available to everyone: https://www.hackerrank.com/test/78113p6eaqn
I also had this question on an assessment. The problem is that the input for items is a 2D list of strings, not a list of [name: string, relevance: int, price: int]. Thus when you called sort you were sorting strings of numbers instead of actual numbers, which led to unexpected results. For example:
>>> nums = list(range(1, 6)) + list(range(10, 60, 10))
>>> nums = list(map(str, nums))
>>> nums
['1', '2', '3', '4', '5', '10', '20', '30', '40', '50']
>>> nums.sort()
>>> nums
['1', '10', '2', '20', '3', '30', '4', '40', '5', '50']
A small fix would be to change the key function so that it converts relevance and price (columns 1 and 2) to ints while leaving name (column 0) alone.
sortedItems = sorted(items, key=lambda item: int(item[sortParameter]) if sortParameter else item[sortParameter], reverse=sortOrder)

What is the best way to store the results of str.split() into a dictionary as part of a list comprehension? [duplicate]

This question already has answers here:
How to split a string within a list to create key-value pairs in Python
(5 answers)
Closed 4 years ago.
Given the following sample data:
values=['A 1','B 2','C 3']
I want to create a dictionary where A maps to 1, B to 2, and C to 3. The following works, but there is repetition:
my_dict={value.split()[0]:value.split()[1] for value in values}
The repetition of value.split() looks ugly. Is there a way to more elegantly create the dictionary without repeating value.split()?
Two ways I can think of:
>>> {k:v for k,v in (s.split() for s in values)}
{'A': '1', 'B': '2', 'C': '3'}
>>> dict(s.split() for s in values)
{'A': '1', 'B': '2', 'C': '3'}
I suggesting reading about the dict type: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict; in particular:
Each item in the iterable must itself be an iterable with exactly two objects. The first object of each item becomes a key in the new dictionary, and the second object the corresponding value.
as well as the introduction of dict-comprehensions in PEP 274:
The semantics of dict comprehensions can actually be demonstrated in stock Python 2.2, by passing a list comprehension to the built-in dictionary constructor:
>>> dict([(i, chr(65+i)) for i in range(4)])
is semantically equivalent to:
>>> {i : chr(65+i) for i in range(4)}
For a functional solution, you can use dict with map and str.split:
values = ['A 1', 'B 2', 'C 3']
res = dict(map(str.split, values))
{'A': '1', 'B': '2', 'C': '3'}
you can do this way pythonic:
>>> values =['A 1','B 2','C 3']
>>> dict(map(str.split, values))
{'A': '1', 'C': '3', 'B': '2'}
str.split([sep[, maxsplit]])
Return a list of the words in the string, using sep as the delimiter string. If maxsplit is given, at most maxsplit splits are done (thus, the list will have at most maxsplit+1 elements). If maxsplit is not specified or -1, then there is no limit on the number of splits (all possible splits are made).
If sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, '1,,2'.split(',') returns ['1', '', '2']). The sep argument may consist of multiple characters (for example, '1<>2<>3'.split('<>') returns ['1', '2', '3']). Splitting an empty string with a specified separator returns [''].
map(function, iterable, ...)
Apply function to every item of iterable and return a list of the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. If one iterable is shorter than another it is assumed to be extended with None items. If function is None, the identity function is assumed; if there are multiple arguments, map() returns a list consisting of tuples containing the corresponding items from all iterables (a kind of transpose operation). The iterable arguments may be a sequence or any iterable object; the result is always a list.
you can see that dictionary is not in ordered as your list. Using collections.orderedDict we can retain the order of the input given.
>>> import collections
>>> values =['A 1','B 2','C 3']
>>> my_ordered_dict = collections.OrderedDict(map(str.split, values))
>>> my_ordered_dict
OrderedDict([('A', '1'), ('B', '2'), ('C', '3')])

Find matching items in nested list

I'm trying to match a list of items to another list of items of a different dimension and print an element from the second list if the item is matched. For example:
stlist=['6', '3', '4', '2', '5', '1']
ndlist=[['Tom', '1'], ['Joh', '2'], ['Sam', '3'], ['Tommy','4'], ['Nanni', '5'], ['Ron', '6']]
My outputlist is producing the names in the ascending order of my stlist.
i.e Tom, Joh, Sam, Tommy, Nanni, Ron but I want the outputlist to be in the same order as the stlist.
My Python code is:
for sublist in ndlist:
for element in stlist:
if element in sublist[1]:
print(sublist[0])
The outputlist displayed from the above codes is: Tom, Joh, Sam, Tommy, Nanni, Ron instead of
outputlist = [Ron, Sam, Tommy, Joh, Nanni, Tom]
So it's actually sorting in ascending order my 1stlist and printing the names from the 2ndlist in that order.But if my stlist was in ascending order the outputlist would be fine.
Can anyone tell me why please and how should I modify the codes to get my desired outputlist.
Try to rearrange your for loops:
for element in stlist:
for sublist in ndlist:
if element in sublist[1]:
print (sublist[0])
Also, the if statement should maybe be like this: if element == sublist[1]: or else the element '1' would be found in some ndlist element like this one: ['foo', '10']
Furthermore, this solution is not the most efficient with large lists. To make it more efficient you could try something like sorting the ndlist and performing binary search to check if an element exists.
You could use sorted and a custom sort key (a Lambda function) to do this:
>>> [i[0] for i in sorted(ndlist, key = lambda x:stlist.index(x[1]))]
['Ron', 'Sam', 'Tommy', 'Joh', 'Nanni', 'Tom']
This line of code sorts ndlist using the position of the numbers in stlist as the sort key, then a list comprehension builds a new list containing only the names.
Instead of nesting loops or sorting you could also create a mapping with one linear run through ndlist and then use another linear run through stlist to build the result list:
mapping = dict((b, a) for a, b in ndlist)
result = [mapping[x] for x in stlist]
print(result)

how to add value to a tuple?

I'm working on a script where I have a list of tuples like ('1','2','3','4'). e.g.:
list = [('1','2','3','4'),
('2','3','4','5'),
('3','4','5','6'),
('4','5','6','7')]
Now I need to add '1234', '2345','3456' and '4567' respectively at the end of each tuple. e.g:
list = [('1','2','3','4','1234'),
('2','3','4','5','2345'),
('3','4','5','6','3456'),
('4','5','6','7','4567')]
Is it possible in any way?
Tuples are immutable and not supposed to be changed - that is what the list type is for.
However, you can replace each tuple using originalTuple + (newElement,), thus creating a new tuple. For example:
t = (1,2,3)
t = t + (1,)
print(t)
(1,2,3,1)
But I'd rather suggest to go with lists from the beginning, because they are faster for inserting items.
And another hint: Do not overwrite the built-in name list in your program, rather call the variable l or some other name. If you overwrite the built-in name, you can't use it anymore in the current scope.
Based on the syntax, I'm guessing this is Python. The point of a tuple is that it is immutable, so you need to replace each element with a new tuple:
list = [l + (''.join(l),) for l in list]
# output:
[('1', '2', '3', '4', '1234'),
('2', '3', '4', '5', '2345'),
('3', '4', '5', '6', '3456'),
('4', '5', '6', '7', '4567')]
As mentioned in other answers, tuples are immutable once created, and a list might serve your purposes better.
That said, another option for creating a new tuple with extra items is to use the splat operator:
new_tuple = (*old_tuple, 'new', 'items')
I like this syntax because it looks like a new tuple, so it clearly communicates what you're trying to do.
Using splat, a potential solution is:
list = [(*i, ''.join(i)) for i in list]
In Python, you can't. Tuples are immutable.
On the containing list, you could replace tuple ('1', '2', '3', '4') with a different ('1', '2', '3', '4', '1234') tuple though.
As other people have answered, tuples in python are immutable and the only way to 'modify' one is to create a new one with the appended elements included.
But the best solution is a list. When whatever function or method that requires a tuple needs to be called, create a tuple by using tuple(list).
I was going through some details related to tuple and list, and what I understood is:
Tuples are Heterogeneous collection data type
Tuple has Fixed length (per tuple type)
Tuple are Always finite
So for appending new item to a tuple, need to cast it to list, and do append() operation on it, then again cast it back to tuple.
But personally what I felt about the Question is, if Tuples are supposed to be finite, fixed length items and if we are using those data types in our application logics then there should not be a scenario to appending new items OR updating an item value in it.
So instead of list of tuples it should be list of list itself, Am I right on this?
list_of_tuples = [('1', '2', '3', '4'),
('2', '3', '4', '5'),
('3', '4', '5', '6'),
('4', '5', '6', '7')]
def mod_tuples(list_of_tuples):
for i in range(0, len(list_of_tuples)):
addition = ''
for x in list_of_tuples[i]:
addition = addition + x
list_of_tuples[i] = list_of_tuples[i] + (addition,)
return list_of_tuples
# check:
print mod_tuples(list_of_tuples)
A lot of people is writing tuples are immutables... and that's right! But there is this code:
tuple = ()
for i in range(10):
tuple += (i,)
print(tuple)
And It works! Why? Well.. that's because in the code there is a "=". Every time you use the operator "=" in Python you assign a new value to an object: you create a new variable!
So you are not modifying the old tuple: you are creating a new one, with the same name (tuple), with value the old one plus something more.
OUTPUTS = []
for number in range(len(list_of_tuples))):
tup_ = list_of_tuples[number]
list_ = list(tup_)
item_ = list_[0] + list_[1] + list_[2] + list_[3]
list_.append(item_)
OUTPUTS.append(tuple(list_))
OUTPUTS is what you desire
In case of tuple and list, a very simple way can be (suppose) :
tpl = ( 3, 6, 9)
lst = [ 12, 15, 18]
my_tuple = tpl + tuple(lst)
print(my_tuple)

Categories