Making a vector of specific length with random numbers - python-3.x

I tried writing a program that would give me the i,j and k components of a vector of a specified magnitude.
import random
import math
while True:
a = random.uniform(0,1000)
b = random.uniform(0,1000)
c = random.uniform(0,1000)
d = 69.420
if math.sqrt(a**2 + b**2 + c**2) == d:
print(a,b,c)
break
But it seems that this program might take literally forever to give me an output.
What would faster or possible solution be?
#Update
import random
import math
while True:
a2 = random.uniform(1,1000)
b2 = random.uniform(1,1000)
c2 = random.uniform(1,1000)
d = 69.420
d2 = a2 + b2 + c2
a2 *= d/d2
b2 *= d/d2
c2 *= d/d2
a = math.sqrt(a2)
b = math.sqrt(b2)
c = math.sqrt(c2)
if math.sqrt(a**2 + b**2 + c**2) == d:
print(a,b,c)
break
As per suggested, but still taking a very long time to compute

Get three random numbers a2, b2, and c2. Those are your random squares. Add them up to get d2. You want the sum of the squares to be d squared, so multiply a2, b2, and c2 by d*d/d2. These are your new squares that add up to d squared. Now assign the square roots of a2, b2, and c2 to a, b, and c. Does that make sense?
Avoid dividing by zero. If d2 happens to be zero, just start over.

Related

Calculate length of all segments in polygon using geopandas

I have this little issue I am trying to solve and I have looked everywhere for an answer. It seems odd that I cannot find it, but it might just be me.
So, I have this dataframe
df=
id x_zone y_zone
0 A1 65.422080 48.147850
1 A1 46.635708 51.165745
2 A1 46.597984 47.657444
3 A1 68.477700 44.073700
4 A3 46.635708 54.108190
5 A3 46.635708 51.844770
6 A3 63.309560 48.826878
7 A3 62.215572 54.108190
that I convert into a geopandas dataframe:
df_geometry = gpd.GeoDataFrame(geometry=df.groupby('id').apply(
lambda g: Polygon(gpd.points_from_xy(g['x_zone'], g['y_zone']))))
df_geometry = df_geometry.reset_index()
print(df_geometry)
which returns:
id geometry
A1 POLYGON ((65.42208 48.14785, 46.63571 51.16575...
A3 POLYGON ((46.63571 54.10819, 46.63571 51.84477...
and for which I can compute the area and the perimeter:
df_geometry["area"] = df_geometry['geometry'].area
df_geometry["perimeter"] = df_geometry['geometry'].length
which gives:
id geometry area perimeter
0 A1 POLYGON ((65.42208 48.14785, 46.63571 51.16575... 72.106390 49.799695
1 A3 POLYGON ((46.63571 54.10819, 46.63571 51.84477... 60.011026 40.181476
Now, to the core of my problem: IF one can calculate the length, surely the length of each segment of the polygons is being calculated. How can I retrieve this?
I understand that for very complicated polygons (e.g. country maps, this might be problematics to store). Anyone with an idea?
Here is the runnable code that shows all the steps to create a dataframe that contains required segment lengths.
from io import StringIO
import geopandas as gpd
import pandas as pd
from shapely.geometry import Point, Polygon
import numpy as np
dats_str = """index id x_zone y_zone
0 A1 65.422080 48.147850
1 A1 46.635708 51.165745
2 A1 46.597984 47.657444
3 A1 68.477700 44.073700
4 A3 46.635708 54.108190
5 A3 46.635708 51.844770
6 A3 63.309560 48.826878
7 A3 62.215572 54.108190"""
# read the string, convert to dataframe
df1 = pd.read_csv(StringIO(dats_str), sep='\s+', index_col='index') #good for space/s separation
gdf = gpd.GeoDataFrame(geometry=df1.groupby('id')
.apply(lambda g: Polygon(gpd.points_from_xy(g['x_zone'], g['y_zone']))))
gdf = gdf.reset_index() #bring `id` to `column` status
# Facts about polygon outer vertices
# - first vertex is the same as the last
# - to get segments, ignore zero-th point (use it as from_point in next row)
# create basic lists for creation of new dataframe
indx = [] # for A1, A3
sequ = [] # for seg order
pxy0 = [] # from-point
pxy1 = [] # to-point
for ix,geom in zip(gdf.id, gdf.geometry):
num_pts = len(geom.exterior.xy[0])
#print(ix, "Num points:", num_pts)
old_xy = []
for inx, (x,y) in enumerate(zip(geom.exterior.xy[0],geom.exterior.xy[1])):
if (inx==0):
# first vertex is the same as the last
pass
else:
indx.append(ix)
sequ.append(inx)
pxy0.append(Point(old_xy))
pxy1.append(Point(x,y))
old_xy = (x,y)
# Create new geodataframe
pgon_segs = gpd.GeoDataFrame({"poly_id": indx,
"vertex_id": sequ,
"fr_point": pxy0,
"to_point": pxy1}, geometry="to_point")
# Compute segment lengths
# Note: seg length is Euclidean distance, ***not geographic***
pgon_segs["seg_length"] = pgon_segs.apply(lambda row: row.fr_point.distance(row.to_point), axis=1)
The content of pgon_segs:
poly_id vertex_id fr_point to_point seg_length
0 A1 1 POINT (65.42207999999999 48.14785) POINT (46.63571 51.16575) 19.027230
1 A1 2 POINT (46.635708 51.165745) POINT (46.59798 47.65744) 3.508504
2 A1 3 POINT (46.597984 47.657444) POINT (68.47770 44.07370) 22.171270
3 A1 4 POINT (68.4777 44.0737) POINT (65.42208 48.14785) 5.092692
4 A3 1 POINT (46.635708 54.10819) POINT (46.63571 51.84477) 2.263420
5 A3 2 POINT (46.635708 51.84477) POINT (63.30956 48.82688) 16.944764
6 A3 3 POINT (63.30956 48.826878) POINT (62.21557 54.10819) 5.393428
7 A3 4 POINT (62.215572 54.10819) POINT (46.63571 54.10819) 15.579864

User input list values in python 3.4

This code works but it's not what I need
lst = range(1,17)
It uses from 1 to 16 to do some calculations but in fact I want to specify the values, when I type them inside the code it works:
lst = (14, 1, 6, 8)
but what I want is the user who must choose which values to be in the list by inputting them
I have tried this but it does not works
lst = (a1, a2, a3)
a1 = int(input("number 1: "))
a2 = int(input("number 2: "))
a3 = int(input("number 3: "))
You have to switch the order of your lines of code:
a1 = int(input("number 1: "))
a2 = int(input("number 2: "))
a3 = int(input("number 3: "))
lst = (a1, a2, a3)
Python will execute your example code line-by-line in top-down order, so if you want to create list/tuple from inputed values the creation has to be as last one.

elegant way to iterate & compare in Spark DataFrame

I have a Spark DataFrame with 2 columns: C1:Seq[Any] and C2:Double. I want to
Sort by length of C1.
For each element c1 in C1, compare with every other element in C1 that is longer than c1.
2.1 If c1 is contained in an another element cx, then compare c2 with c2x.
2.2 If c2 > c2x, then filter out (c1x, c2x).
Is there an elegant way to achieve this?
Sample Input:
C1 C2
ab 1.0
abc 0.5
Expected output:
C1 C2
ab 1.0
Contain = subset. e.g. ab is contained in abc.
I have a Spark DataFrame with 2 columns: C1:Seq[Any] and C2:Double
val rdd = sc.parallelize(List(("ab", 1.0), ("abc", 0.5)))
Sort by length of C1.
val rddSorted = rdd.sortBy(_._1.length).collect().distinct
For each element c1 in C1, compare with every other element in C1 that is longer than c1.
2.1 If c1 is contained in an another element cx, then compare c2 with c2x.
2.2 If c2 > c2x, then filter out (c1x, c2x).
val result = for(
(x, y) <- rddSorted;
(a, b) <- rddSorted.dropWhile{case(c,d) => c == x && d == y};
if(a.contains(x) && a.length > x.length && y > b)
)yield (x, y)
Thats all. You should get what you are looking for

How do I solve two equations where one equation has a variable that takes a range of values?

Two equations ---
c + w + u = 50;
c-w/4 = 39
In the above, 'u' takes integer values from 0 to 11. (Why/How the 11? 11 = 50-39).
I need to output a table of values for c and w for each value of u starting with u = 0. The corresponding value of u must also appear across each row of values for c and w.
How do I write a VBA code for this?
Many thanks in advance!
Do a little algebra first:
c-w/4 = 39
c = 39+w/4
c+w+u = 50
39+w/4+w+u = 50
w/4+w+u = 50-39
w/4+w = 11-u
1.25*w = 11-u
w = (11-u)/1.25
Put the u values in column A. In B1 enter:
=(11-A1)/1.25
and copy down. In C1 enter:
=39+B1/4
and copy down.
The w values are in column B and the c values are in column C.

How to sum constants if the values of a row contian a specific value in excel?

I have the following row in excel:
12 4 12p 12a 12b
I need to sum this elements with their values from the legend.
12 = 12;
4 = 4;
12p = 12,5;
12a = 12,2;
12b = 12,3;
For example
=12 + 4 + 12,5 + 12,2 + 12,3
Any ideas?
If you have all the elements within one cell as a single string of text, the optimal approach would be to start by using text-to-column to split them up. So you'll have 12 in A, 4 in B, 12p in C, 12a in D, 12b in E. If that's not an option, I can show you string manipulations that can be an alternative.
You'll need to turn your "legend" into a look-up table, (perhaps on sheet2?), with column A having: p, a, b, etc.. and column B having the relative values.
Once that's done, place this formula on sheet1, in F column:
=A2+IFERROR(VLOOKUP(RIGHT(A2),Sheet2!$A:$B,2,FALSE),0)
Then drag it to the right 5 times, and it will have the values of the elements "translated".
You can sum the translated range easily.

Resources