Dividing certain members of a list in python - python

I have a matrix formed by a list of lists and I want to divide each member of the second half of each sublist by the integer in the first 3 members of each sublist. Here is my code:
def matrix():
a=[[12.0, 0.0, 0.0, 12, 156, -108], [0.0, 2.667, 0.0, -5.333, -77.333, 53.333], [0.0, 0.0, -0.0937, -0.0937, -1.4687, 1.0]]
for i in range(len(a)):
a[i] = [v/a[i][i] for v in a[i]]
return a
However, this code divides each entire sublist by the integer found in the first half of each sublist which gives me this output:
[[1.0, 0.0, 0.0, 1.0, 13.0, -9.0], [0.0, 1.0, 0.0, -1.9996250468691417, -28.996250468691414, 19.99737532808399], [-0.0, -0.0, 1.0, 1.0, 15.674493062966913, -10.672358591248665]]
I only want the second part of each sublist divided, not the first half. I need to obtain this output, as you can see the first 3 integers of each sublist must stay the same:
[[12,0,0,1,13,-9],[0,2.667,0,-2,-29,20],[0,0,-0.09375,1,15.6667,-10.6667]]

You can split up your logic into two steps:
Find the integer in the first three numbers.
Divide the second half of each sublist by that number.
def matrix():
a = [[12.0, 0.0, 0.0, 12, 156, -108],
[0.0, 2.667, 0.0, -5.333, -77.333, 53.333],
[0.0, 0.0, -0.0937, -0.0937, -1.4687, 1.0]]
for i in range(len(a)):
divisor = 0
for j in range(3):
if a[i][j]:
divisor = a[i][j]
break
for j in range(len(a[i]) // 2, len(a[i])):
a[i][j] = a[i][j] / divisor
return a
print(matrix())
Output:
[[12.0, 0.0, 0.0, 1.0, 13.0, -9.0], [0.0, 2.667, 0.0, -1.9996250468691417, -28.996250468691414, 19.99737532808399], [0.0, 0.0, -0.0937, 1.0, 15.674493062966913, -10.672358591248665]]

Related

How to find the maximum of sublists in arbitrary nested list?

I have a list C11 containing many sublists. I want to find the maximum element of each sublist. I present the current and expected outputs.
C11 = [[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
for i in range(0,len(C11)):
C2 = max(C11[i])
print(C2)
The current output is
[[353.856161, 0.0, 0.0], [0.0, 294.983702, 126.991664]]
The expected output is:
[[[353.856161],[282.754301]], [[294.983702]]]
In case the depth is completely arbitrary and you want to keep the same nesting structure in the output, here is a recursive function that keeps going in levels until reaching a "leaf" (list with values and not lists) and takes the maximums:
def get_max(l):
res = []
if isinstance(l[0], list):
for sub in l:
res.append(get_max(sub))
else:
res.append(max(l))
return res
print(get_max([[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]))
Will give:
[[[353.856161], [282.754301]], [[294.983702]]]
Use this function in case the nesting-depth of the list is variable.
C11=[[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
def find_max(ls: list) -> list:
# does the list contain only numbers?
if all((isinstance(x, float) for x in ls)):
# if yes return simple max
return [max(ls)]
else:
# apply the function one level deeper
return [find_max(x) for x in ls]
print(find_max(C11))
List Comprehension
Code:-
C11=[[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
res=[[[max(sublist)] for sublist in lis] for lis in C11]
print(res)
Output:
[[[353.856161], [282.754301]], [[294.983702]]]
Here is a quick recursive generalized approach. Should work with any level of varying nesting.
c11 = [[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
result = []
def traverse(arr, result):
if len(arr) > 0:
if type(arr[0]) is list:
# check if item inside list is another list
for i in arr:
result = traverse(i, result)
else:
# if its a list of number, get the max and add it to result
result.append(max(arr))
return result
print(traverse(c11, result))
Using recursive is the best option. Recursive works for any length of list. Used a initial validation to check if list element is empty.
Code:
check=[[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
def recursive_max(lst):
if len(lst) == 0:
return []
if isinstance(lst[0], list):
min_val = []
for val in lst:
min_val.append(recursive_max(val))
return min_val
else:
return [max(lst)]
print(recursive_max(check))
Output:
[[[353.856161], [282.754301]], [[294.983702]]]
C11 array is multi dimension array need put in nested loop
C11 = [[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
for i in range(0, len(C11)):
for j in range(0, len(C11[i])):
C2 = max(C11[i][j])
print(C2)
Output
I have assumed that the depth of the list is random.
I have used a recursive approach to replace a last-level list with a list of its maximum value.
def recurse(l):
for index in range(len(l)):
if type(l[index]) == list:
l[index] = recurse(l[index])
else:
l = [max(l)]
return l
return l
Example:
l = [[5,3,8], [1,2,4], [[[2,4],[11,12]],[5,9]]]
recurse(l)
print(l)
Output:
[[8], [4], [[[4], [12]], [9]]]
Your Example:
C11=[[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
recurse(C11)
print(C11)
Output:
[[[353.856161], [282.754301]], [[294.983702]]]
Note: The function updates the list inplace so if you want to restore the list, use a copy of the old list.
Code:
C11=[[[353.856161, 0.0, 0.0], [0.0, 0.0, 282.754301, 0.0]], [[0.0, 294.983702, 126.991664]]]
C2=[]
for i in range(0,len(C11)):
C2.insert(i, [])
for j in range(0,len(C11[i])):
C2[i].insert(j, [])
C2[i][j].insert(0, max(C11[i][j]))
print(C2)
Output:
[[[353.856161], [282.754301]], [[294.983702]]]

How to sum certain floats in a list

I wonder how to sum up only the floats in this list,
list = ['abc', 3.0, 2.0, 2.0, 0.0, 1.0, 0.0, 0.0]
I can't find out how to exclude the first string. I would like to do something with
range(1, len(list))
as it will need to work on lists with longer lengths, maybe something similar to it with the same effect? For python 3
You can use a generator in sum() and isinstance() to check if something is a float.
>>> lst = ['abc', 3.0, 2.0, 2.0, 0.0, 1.0, 0.0, 0.0]
>>> sum(x for x in lst if isinstance(x, float))
8.0
Note you should not use list as a variable name as it will overwrite the built in list class.
my_list = ['abc', 3.0, 2.0, 2.0, 0.0, 1.0, 0.0, 0.0]
sum = 0
for i in my_list:
if type(i) is float:
sum += i
print(sum)
This will result the sum to 8.0

Plot and fill 3D volumes in Python

I am working with some 3D (volumetric) data using Python, and for every tetrahedron, I have not only the vertices's coordinates but also a fourth dimension which is the value of some parameter for that tetrahedron volume.
For example:
# nodes coordinates that defines a tetrahedron volume:
x = [0.0, 1.0, 0.0, 0.0]
y = [0.0, 0.0, 1.0, 0.0]
z = [0.0, 0.0, 0.0, 1.0]
# Scaler value of the potential for the given volume:
c = 100.0
I would like to plot a 3D volume (given by the nodes coordinates) filled with some solid color, which would represent the given value C.
How could I do that in Python 3.6 using its plotting libraries?
You can use mayavi.mlab.triangular_mesh():
from mayavi import mlab
from itertools import combinations, chain
x = [0.0, 1.0, 0.0, 0.0, 2.0, 3.0, 0.0, 0.0]
y = [0.0, 0.0, 1.0, 0.0, 2.0, 0.0, 3.0, 0.0]
z = [0.0, 0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 3.0]
c = [20, 30]
triangles = list(chain.from_iterable(combinations(range(s, s+4), 3) for s in range(0, len(x), 4)))
c = np.repeat(c, 4)
mlab.triangular_mesh(x, y, z, triangles, scalars=c)

Accessing elements in a nested list

I have elements in a nested list called "train_data" like in the example:
[0] [0.935897, 1.0, 1.0, 0.928772, 0.053629, 0.0, 39.559883, 0.009494, 0]
[1] [0.467681, 1.0, 1.0, 0.778987, 0.069336, 0.0, 56.571999, 0.024675, 0]
[2] [0.393258, 1.0, 1.0, 0.843201, 0.068779, 0.0, 66.866669, 0.069206, 1]
I would like to access all rows with the first 8 columns (all but the last one), and all rows with only the last column. I need to this without for loops, in a single line of code.
I tried something like this:
print train_data[0][:]
print train_data[:][0]
but this gives me the same result:
[0.935897, 1.0, 1.0, 0.928772, 0.053629, 0.0, 39.559883, 0.009494, 0]
[0.935897, 1.0, 1.0, 0.928772, 0.053629, 0.0, 39.559883, 0.009494, 0]
Could someone help me please?
Edit:
Sorry, the expected output for the first query is:
[0.935897, 1.0, 1.0, 0.928772, 0.053629, 0.0, 39.559883, 0.009494]
[0.467681, 1.0, 1.0, 0.778987, 0.069336, 0.0, 56.571999, 0.024675]
[0.393258, 1.0, 1.0, 0.843201, 0.068779, 0.0, 66.866669, 0.069206]
and for the second query is:
[0]
[0]
[1]
you can use [:-1] slicing for get all elements except the last one !
>>> l1=[0.935897, 1.0, 1.0, 0.928772, 0.053629, 0.0, 39.559883, 0.009494, 0]
>>> l2=[0.467681, 1.0, 1.0, 0.778987, 0.069336, 0.0, 56.571999, 0.024675, 0]
>>> l3=[0.393258, 1.0, 1.0, 0.843201, 0.068779, 0.0, 66.866669, 0.069206, 1]
>>> l=[l1,l2,l3]
>>> [i[:-1] for i in l]
[[0.935897, 1.0, 1.0, 0.928772, 0.053629, 0.0, 39.559883, 0.009494], [0.467681, 1.0, 1.0, 0.778987, 0.069336, 0.0, 56.571999, 0.024675], [0.393258, 1.0, 1.0, 0.843201, 0.068779, 0.0, 66.866669, 0.069206]]
Is there really a good reason to do this in a oneliner? I mean why is that a requirement?
print [i[:-1] for i in l] # All rows with all cols - 1
print [i[-1] for i in l] # All rows with last col
But even if the loop is not explicit with a for, it's implicit as a comprehensive list...
edit: 1 → -1 for second line of code, my mistake
I think you are expecting this
L1 = [x[0:-1] for x in train_data]
L2 = [x[-1] for x in train_data]
for x in L1:
print x
for x in L2:
print [x]

Python list of lists not retaining information, which is once stored successfully

I have a file I am reading which goes like this :
/m/09c7w0
9.15810037736e+12 3957219322.11
9085777777.78 2585810931.38
10000000000.0 0.0
3.6e+16 0.0
4.65962485769e+12 8.39090575309e+11
0.540909090909 0.25489586271
3.99875996113 2.79866987366
41.3330962083 29.8486587064
10000000000.0 0.0
2341215333.91 88390569.3568
/m/09c7w0
9.15810037736e+12 3957219322.11
9085777777.78 2585810931.38
10000000000.0 0.0
3.6e+16 0.0
4.65962485769e+12 8.39090575309e+11
0.540909090909 0.25489586271
3.99875996113 2.79866987366
41.3330962083 29.8486587064
10000000000.0 0.0
2341215333.91 88390569.3568
Now I am reading this file and storing it in a list of lists. Below is the Python code. In the elif portion, float(temp[0]) transfers the correct values to the country_catgs_stats[c][2*v] and so does float(temp[1][:-1]) transfer the correct values to the country_catgs_stats[c][2*v+1] and hence prints everything alright.
#!/usr/bin/env python
country_stats = open("country_stats")
lines_all = country_stats.readlines()
temp = [0.0] * 22
country_catgs_stats = [temp] * 241
c = 0
v = 0
c_inc = False
for line in lines_all:
temp = line.split('\t')
if len(temp) == 1 and c_inc == True:
c_inc = False
c += 1
elif len(temp) == 2:
if c_inc == False:
c_inc = True
v = 0
country_catgs_stats[c][2*v] = float(temp[0])
country_catgs_stats[c][2*v+1] = float(temp[1][:-1])
print c, '\t', 2*v, '\t', float(temp[0]), country_catgs_stats[c][2*v], '\t', 2*v+1, '\t', float(temp[1][:-1]), country_catgs_stats[c][2*v+1]
v += 1
for i in range(0, 240):
for j in range(0, 10):
print country_catgs_stats[i][2*j], '\t', country_catgs_stats[i][2*j+1]
But once out of the 1st for loop, when I am printing the list of lists country_catgs_stats[c] second time, it prints nothing - everything is printed as :
0.0 0.0
0.0 0.0
...
0.0 0.0
0.0 0.0
I am running against time for a submission and this problem is driving me bonkers for the last 3.5 hours. I'm taking a refuge here. Someone please help.
PS. Is the definition for country_catgs_stats also correct - or is there an error lurking there ?
The definition for country_catgs_stats is not correct. Try the same thing with smaller numbers:
>>> temp = [0.0] * 5
>>> country_catgs_stats = [temp] * 5
>>> country_catgs_stats
[[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0]]
So far so good. Let me set a single thing in temp:
>>> temp[0]=9
>>> country_catgs_stats
[[9, 0.0, 0.0, 0.0, 0.0], [9, 0.0, 0.0, 0.0, 0.0], [9, 0.0, 0.0, 0.0, 0.0], [9, 0.0, 0.0, 0.0, 0.0], [9, 0.0, 0.0, 0.0, 0.0]]
>>>
Same effect if the assignment is into country_catgs_stats:
>>> country_catgs_stats[0][1] = 8
>>> country_catgs_stats
[[9, 8, 0.0, 0.0, 0.0], [9, 8, 0.0, 0.0, 0.0], [9, 8, 0.0, 0.0, 0.0], [9, 8, 0.0, 0.0, 0.0], [9, 8, 0.0, 0.0, 0.0]]
>>>
See how every list has changed. There aren't five lists, but one list referenced five times. Or in your code, the same list linked 241 times.
It works as it runs, because you assign and print immediately, before overwriting it the next time through the loop.
Try
country_catgs_stats = []
for i in range(241):
country_catgs_stats.append([0.0] * 22)
How vicious (*) !
You tried to solve the problem of reusing the inner list in a list of list by preallocating the list of list (country_catgs_stats). But the way you did is even worse, because is is 241 time the same inner temp list !
Hopefully it should be easy to fix by simply writing :
country_catgs_stats = [ temp[:] for i in range(241) ]
because now you get 241 copies of temp ...
(*) not you of course, but the mistake :-)

Categories

Resources