Python- printing n'th level sublist - python

I have a complicated list arrangement. There are many lists, and some of them have sub-lists. Now, some of the elements from the aforementioned lists are to be printed. What makes it more complicated is, the index of the value to be printed is in an excel file, as shown here:
[list_1,1,2] #Means - list[1][2] is to be printed (sub-lists are there)
[list_2,7] #Means - list_2[7] is to be printed (no sub-list)
................
[list_100,3,6] #Means list_100[3][6] is to be printed (sub list is there)
The number of the lists is so long, so that I was using a for loop and multiple if statements. For example (pseudo code):
for i in range(100): #because 100 lists are there in excel
if len(row_i) == 3:
print(list_name[excel_column_1_value][excel_column_2_value])
else:
print(list_name[excel_column_1_value])
Please note that, the excel sheet is only to get the list name and index, the lists are all saved in the main code.
Is there any way to avoid the if statements and automate that part as well ? Asking because, the if condition value is only based on the length given by the excel sheet. Thanks in advance.

Suppose you have data like this:
data = {
"list1": [[100, 101, 102], [110, 111, 112], [120, 121, 123]],
"list2": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
"list3": [[200, 201, 202], [210, 211, 212], [220, 221, 223]],
}
If it is homework, your teacher probably want you to solve it using recursion, but I recommend using an iterative version in Python unless you can assure you would not stack more than 999 calls:
fetch_element(data, listname, *indices):
value = data[listname]
for index in indices:
value = value[index]
return value
Then you have the list of elements you want:
desired = [
["list1", 0, 0],
["list2", 7],
["list3", 2, 2],
]
Now you can do:
>>> [fetch_element(data, *line) for line in desired]
[100, 7, 223]
Which is the same as:
>>> [data["list1"][0][0], data["list2"][7], data["list3"][2][2]]
[100, 7, 223]

Can you post a better example? how does your list look like and what's the desired output when printing?
You can open the file, read the indexes and lists names you want to print into a list and iterate that list to print what you want.
There are many ways to print a list a simple one, you can use:
mylist = ['hello', 'world', ':)']
print ', '.join(mylist)
mylist2 = [['hello', 'world'], ['Good', 'morning']]
for l in mylist2:
print(*l)

Related

Compare list of list with dictionary

My list of list is
candidates= [[714, 1023, 768, 1078], [803, 938, 868, 995]]
My dictionary is:
main_dict = {(1561, 48, 1623, 105): [[[1592, 58]],
[[1591, 59]],
[[1585, 59]],
[[1600, 58]]],
(714, 1023, 768, 1078): [[[1, 5]],
[[2, 6]],
[[3, 3]],
[[4, 3]]],
(803, 938, 868, 995): [[[14, 5]],
[[22, 64]],
[[34, 31]],
[[43, 32]]]
}
I would like to have 2 lists, candidate_values_exists_in_dict_key which contains the corresponding values of candidates that exist in main_dict, and the other list contains the values that are in main_dict but not in candidate_values_exists_in_dict_key.
Here is what I tried, very cluttering and slow. Can someone have a faster way? Furthermore, how can I have an else statement that has the list of keys v which do not exist in candidate_values_exists_in_dict_key but in main_dict?
It is guaranteed that the candidates values will always be in the main_dict keys, and in the same order of appearance as the candidates.
candidate_values_exists_in_dict_key = []
values_of_main_dict_not_in_candidates_values_list=[]
for x in candidates:
for k, v in main_dict.items():
if x == list(k):
candidate_values_exists_in_dict_key.append(v)
Just a normal list comprehension with dict lookup would do fine. There isn't any need for nested loops
candidate_values_exists_in_dict_key = [main_dict[tuple(c)] for c in candidates]
values_of_main_dict_not_in_candidates_values_list = [v for k,v in main_dict.items() if list(k) not in candidates]
Given that you want to output a list of values that are not in the candidates in addition to a list of those that are, you are going to have to iterate through the dictionary in one form or another in any case.
Therefore the code in the question is basically fine. But you could improve it slightly by using a set of the candidates (converted to the tuples used as dictionary keys) to test inclusion, rather than having nested loops. Because you know that these are used as dictionary keys, you also know that they can be used as elements of a set.
candidate_tuples = set(map(tuple, candidates))
candidate_values_exists_in_dict_key = []
values_of_main_dict_not_in_candidates_values_list = []
for k, v in main_dict.items():
if k in candidate_tuples:
candidate_values_exists_in_dict_key.append(v)
else:
values_of_main_dict_not_in_candidates_values_list.append(v)

Python intersection of arrays in dictionary

I have dictionary of arrays as like:
y_dict= {1: np.array([5, 124, 169, 111, 122, 184]),
2: np.array([1, 2, 3, 4, 5, 6, 111, 184]),
3: np.array([169, 5, 111, 152]),
4: np.array([0, 567, 5, 78, 90, 111]),
5: np.array([]),
6: np.array([])}
I need to find interception of arrays in my dictionary: y_dict.
As a first step I cleared dictionary from empty arrays, as like
dic = {i:j for i,j in y_dict.items() if np.array(j).size != 0}
So, dic has the following view:
dic = { 1: np.array([5, 124, 169, 111, 122, 184]),
2: np.array([1, 2, 3, 4, 5, 6, 111, 184]),
3: np.array([169, 5, 111, 152]),
4: np.array([0, 567, 5, 78, 90, 111])}
To find interception I tried to use tuple approach as like:
result_dic = list(set.intersection(*({tuple(p) for p in v} for v in dic.values())))
Actual result is empty list: [];
Expected result should be: [5, 111]
Could you please help me to find intersection of arrays in dictionary? Thanks
The code you posted is overcomplex and wrong because there's one extra inner iteration that needs to go. You want to do:
result_dic = list(set.intersection(*(set(v) for v in dic.values())))
or with map and without a for loop:
result_dic = list(set.intersection(*(map(set,dic.values()))))
result
[5, 111]
iterate on the values (ignore the keys)
convert each numpy array to a set (converting to tuple also works, but intersection would convert those to sets anyway)
pass the lot to intersection with argument unpacking
We can even get rid of step 1 by creating sets on every array and filtering out the empty ones using filter:
result_dic = list(set.intersection(*(filter(None,map(set,y_dict.values())))))
That's for the sake of a one-liner, but in real life, expressions may be decomposed so they're more readable & commentable. That decomposition may also help us to avoid the crash which occurs when passed no arguments (because there were no non-empty sets) which defeats the smart way to intersect sets (first described in Best way to find the intersection of multiple sets?).
Just create the list beforehand, and call intersection only if the list is not empty. If empty, just create an empty set instead:
non_empty_sets = [set(x) for x in y_dict.values() if x.size]
result_dic = list(set.intersection(*non_empty_sets)) if non_empty_sets else set()
You should be using numpy's intersection here, not directly in Python. And you'll need to add special handling for the empty intersection.
>>> intersection = None
>>> for a in y_dict.values():
... if a.size:
... if intersection is None:
... intersection = a
... continue
... intersection = np.intersect1d(intersection, a)
...
>>> if intersection is not None:
... print(intersection)
...
[ 5 111]
For the case where intersection is None, it means that all of the arrays in y_dict had size zero (no elements). In this case the intersection is not well-defined, you have to decide for yourself what the code should do here - probably raise an exception, but it depends on the use-case.

calculating a class avg from a file

For this function, I want the class average for each assignment. I get this error when I try to test my function. Can anyone please help me fix this?
I want to go through the columns and have something like this. After I split the list, I want to interleave the grades of the assignments and add the corresponding items. How do I do that and then calculate the average?
I want to have [99, 88, 77, 66][11, 22, 33, 44][78, 58, 68, 88]into [99, 11, 78][88, 22, 58][77, 33, 68][66, 44, 88]
for item in range(grades_list[4:]):
builtins.TypeError: 'list' object cannot be interpreted as an integer
Here is the file for my function.
Last Name,First Name,Student No.,uTORid,A1,A2,A3,A4
Smith, Joe,9911991199,smithjoe9,99,88,77,66
Ash, Wood,9912334456,ashwood,11,22,33,44
Full, Kare,9913243567,fullkare,78,58,68,88
def class_avg(open_file):
'''(file) -> list of float
Return a list of assignment averages for the entire class given the open
class file. The returned list should contain assignment averages in the
order listed in the given file. For example, if there are 3 assignments
per student, the returned list should 3 floats representing the 3
averages.
[a1_avg, a2_avg, a3_avg, a4_avg]
[62.666666666666664, 56.0, 59.333333333333336, 66.0]
'''
new_list = []
for line in open_file:
grades_list = line.split(',')
for item in range(grades_list[4:]):
total = sum(grades_list[4:][item])
avg = total/len(grades_list[4:])
new_list.append(avg)
return new_list
There are a couple problems in your code.
You need to skip the header line ("Last Name,First Name,Student No.,uTORid,A1,A2,A3,A4")
You're also calculating multiple averages per student (for the first row, your code essentially does (9 + 9) / 2, (8 + 8) / 2, etc)
Also, it seems like you are trying to read down the columns, but that doesn't work
Something like this might work for you:
averages = []
with open('class_avg.csv') as fp:
next(fp) # skip header row
reader = csv.reader(fp)
for student_row in reader:
grades = student_row[4:] # extract columns 4, 5, 6, and 7 all at once
total = sum(float(grade) for grade in grades)
average = total / len(grades)
averages.append(average)
print(averages)
Create a 2d list .....
Read all the lines and then just do computation on the colomns you want output for ...
Accessing the column is something like
#example in python console
>>> list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> new_list = [item[1] for item in list]
>>> new_list
[2, 5, 8]

Moving odd numbers to the end of a list in Python, strange outcome [duplicate]

This question already has answers here:
Strange result when removing item from a list while iterating over it
(8 answers)
Closed 7 years ago.
I'm trying to move the odd numbers in this list to the end without using an external list. When I run the code, it moves half of the odd numbers over, and leaves the other half where they were. The overall output is correct if I run the code twice on the list, but I should only have to run it once, right? What am I doing wrong?
a = [3, 4, 55, 13, 6, 19, 33, 10, 11, 45]
for ind, val in enumerate(a):
if val % 2 != 0:
a.pop(ind)
a.append(val)
print a
Thanks.
This is because, as a general rule, you shouldn't iterate through and modify the same list at the same time. The indices get thrown off!
As you go through and modify the list, not all of the elements actually get cycled through. The a that you are popping is a different list with different indicies after your first change to the list, but you are still using the enumeration of the original version for your loop.
You could use pythons sorting methods (sorted() or someList.sort()) and pass a special key function to it:
>>> sorted(a, key = lambda element: element%2 != 0)
[4, 6, 10, 3, 55, 13, 19, 33, 11, 45]
This is possible because Python sorts are guaranteed to be stable und therefore when multiple records have the same key, their original order is preserved.
Your approach has two problems,
you modify the list on which you iterate
you don't test if the number that slides into the position occupied by an odd number is odd itself
To obviate with 1., you simply can iterate on the indices of your list but to obviate 2., you must start from the end of the list and going towards the beginning, using negative indices.
Executing the following code
a = [3, 4, 55, 13, 6, 19, 33, 10, 11, 45]
for i in range(len(a)):
j = -1-i
if a[j]%2:
a.append(a[j]) ; a.pop(j-1) # j-1 because our list is temporarily longer...
print a
gives you the following output
[4, 6, 10, 45, 11, 33, 19, 13, 55, 3]

Comparing nested lists

I have two lists, one of the form:
[a1, b1, [[c1, d1, e1], [f1, g1, h1], etc, etc], etc]
and the other, a dictionary, whose entries are in the form:
[[a2, b2, c2], [d2, e2, f2], etc, etc].
I need to compare the first entries of those two sub lists there and find any which are the same, and any in the first which don't appear at all in the second.
Foe example, if c1 = d2, I'd want to know, and if f1 isn't equal to either a2 or d2, I'd want to know that.
Anyway, I'm having a bit of trouble implementing this properly, any help would be appreciated.
Thanks!
(I'm not sure how clear the list formats are to understand, sorry if they're still confusing)
CODE SAMPLE:
for row in range(0, len(command[2])):
counter = 0
for nodeRows in range(0, len(nodeTable[command[0]])):
if nodeTable[command[0]][nodeRows][0] == command[2][row][0]:
if ((command[2][row][2]) + 1) < nodeTable[command[0]][nodeRows][2]:
counter += 1
newrow = command[2][row]
newrow[1] = command[1]
newrow[2] = newrow[2] + 1
nodeTable[command[0]][nodeRows] = newrow
change = 'true'
I imagine this doesn't help. The code is a bit monolithic (that's why I didn't post it initially). But I'm basically trying to compare two values. The first values of the items from the list in the 3rd position of another list and the first values of the items from the lists contained in another list.
Um...sorry. I have tried making the code simpler, but it's a bit complicated.
I'm not sure I understand correctly your problem but I'll give it a try.
I guess you need to compare only the first element of every
sublist of 3 elements.
So first I separate all the first elements, then make the comprarisson.
Here is the code with some doctest so you can check if it does what you
are asking:
def compare(l0, l1):
"""
>>> l0 = [1, 2, [[10, 20, 30], [40, 50, 60], [70, 80, 90]], 3]
>>> l1 = [[11, 21, 31], [41, 51, 61], [71, 81, 91]]
>>> compare(l0, l1)
([], [10, 40, 70])
>>> l0 = [1, 2, [[10, 20, 30], [40, 50, 60], [70, 80, 90]], 3]
>>> l1 = [[10, 21, 31], [41, 51, 61], [71, 81, 91]]
>>> compare(l0, l1)
([10], [40, 70])
>>> l0 = [1, 2, [[10, 20, 30], [40, 50, 60], [70, 80, 90]], 3]
>>> l1 = [[10, 21, 31], [40, 51, 61], [70, 81, 91]]
>>> compare(l0, l1)
([10, 40, 70], [])
"""
first_entries_l0 = [x[0] for x in l0[2]]
first_entries_l1 = [x[0] for x in l1]
equals = [x for x in first_entries_l0 if x in first_entries_l1]
unique = [x for x in first_entries_l0 if x not in first_entries_l1]
return equals, unique
To test the code just copy it to a file 'code.py' and run it with:
python -m doctest code.py
You could make it more efficient using sets and looping only once but I'm not even sure this solves your problem so I'll leave that to you.
The answer is: transform your current datastructure to a proper one. Presumably the inputs are be defined by yourself, so you should not write better code to deal with ugly structures, but improve the structures. If you are writing against a bad API, map the API to a useful structure.
You will have to post the whole code to get a proper answer, because the problem is in the definitions. I guess you will have to refactor the whole module and start again, because this is simply bad code.
Some ideas: could command be a tree? a queued list? a matrix? a class? why does the length of the items vary, and why do you want to compare different subitems? Try using classes and override __cmp__.

Categories