Consider the following image
If you want to get a result row containing all steps to get the length of the non-labeled sides, you can do the following:
SELECT
5 AS a, --side 1, triangle 1
7 AS b, --side 2, triangle 1
(5*5) AS a2, --a^2
(7*7) AS b2, --b^2
(5*5)+(7*7) AS c2, --a^2 * b^2 = c^2
SQRT((5*5)+(7*7)) AS c, --√c2 = c
19 AS d, --side 1, triangle 2
24 AS e, --side 2 triangle 2
(19*19) AS d2, --d^2
(24*24) AS e2, --e^2
(19*19)+(24*24) AS f2, --d^2 * e^2 = f^2
SQRT((19*19)+(24*24)) AS f, --√f2 = f
(5*5)+(7*7)+(19*19)+(24*24) AS g2, --c^2 * f^2 = g^2
SQRT((5*5)+(7*7)+(19*19)+(24*24)) AS g --√g2 = g
However, that is CLEARLY very ugly. I'd like to use column substitution, like:
SELECT
5 AS a, --side 1, triangle 1
7 AS b, --side 2, triangle 1
(a*a) AS a2, --a^2
(b*b) AS b2, --b^2
a2+b2 AS c2, --a^2 * b^2 = c^2
SQRT(c2) AS c, --√c2 = c
19 AS d, --side 1, triangle 2
24 AS e, --side 2 triangle 2
(d*d) AS d2, --d^2
(e*e) AS e2, --e^2
d+e AS f2, --d^2 * e^2 = f^2
SQRT(f2) AS f, --√f2 = f
c2+f2 AS g2, --c^2 * f^2 = g^2
SQRT(g2) AS g --√g2 = g
Is there any easy way to do this?
PS Please don't explain how this is a ridiculous use of SQL, I know THAT! This was just the simplest way that I could reduce my problem to be understood. In my scenario, it is much more complex calculations with variables coming from many joined tables, that the results need to be inserted into a summary table with a very rigid structure. Currently, I'm bringing the results out to Node doing the calculations and inserting the data, but that is very VERY slow especially since I to go through the network to get to the database server.
This can be done using common table expressions:
with base_vars (a,b,d,e) as (
values (5),(7),(19),(24)
), var2 (a2, b2, d2, e2) as (
select a*a, b*b, d*d*, e*e
from base_vars,
), var3 (c2, c, f2, f) as (
select a2+b2, SQRT(a2+b2), d+e, sqrt(d+e)
from var2, base_vars
), var3 (g2, g) as (
select c2+f2, sqrt(c2+f2)
from var3
)
select sqrt(g)
from var3;
I am not 100% if I got all variables right, but I think you get the idea.
Another option would be to put that into a PL/pgSQL function.
lateral is a bit shorter than CTEs since it is not necessary to refer to a previous CTE. And the planner can not join the CTEs and the main query into a single plan.
with t (a,b,d,e) as (values (5,7,19,24))
select c, f, sqrt(c2 + f * f)
from
t
cross join lateral
(select a * a, b * b, d * d, e * e) t1 (a2, b2, d2, e2)
cross join lateral
(select a2 + b2, d2 + e2) t2 (c2, f2)
cross join lateral
(select sqrt(c2), sqrt(f2)) t3 (c, f)
;
c | f | sqrt
------------------+------------------+------------------
8.60232526704263 | 30.6104557300279 | 31.7962261911693
Is there XOR operator in Progress?
There is AND, OR and NOT, so, i can code "XOR" like this:
(a OR b) AND NOT (a AND b)
I just want to know if the operator exists (with another name).
Thanks.
Unfortunately, there is no such inbuilt operator in Progress.
You can implement it in the way you said.
There is no built-in XOR. But you might find this helpful:
/* _md5.i
RSA Data Security, Inc. MD5 Message-Digest Algorithm
Progress implementation courtesy Ultramain Systems, Inc.
12/20/00 Andrew Brooman
*/
&IF DEFINED ( BROOMAN_MD5_IMPLEMENTATION ) EQ 0 &THEN
&GLOBAL-DEFINE BROOMAN_MD5_IMPLEMENTATION
/* 12/20/00 Andrew Brooman
NOTES:
1) The MD5 algorithm is described at www.landfield.com/rfcs/rfc1321.html.
2) For ease of debugging, I have used the variable names from the algorithm
as described (e.g. M, A, B, C, D, X, Y, Z, FF, GG, HH, II) hence the
inconsistency with Progress naming conventions (e.g. cMessage).
3) A "word" in this algorithm is a long word (32 bits).
4) Progress INTEGERs are signed long words. Despite the signing,
AND, OR, XOR, NOT, Shift, Add seem to work fine. You will notice
use of negative numbers (e.g. initializing MD5 buffers A B C D) when
the high-order bit needs to be set.
MAX INT = +2147483647
MIN INT = -2147483648
MAX INT + 1 = MIN INT (overflows)
29 Aug 2006 Greg Higgins
Removed Functions to _md5.i
Added Preprocessor BROOMAN_MD5_IMPLEMENTATION
Added some ASSIGN statements
*/
/* bitwise logical operations on long words */
FUNCTION bitAND RETURNS INTEGER (INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
DO n = 1 TO 32:
ASSIGN
b1 = GET-BITS(X, n, 1)
b2 = GET-BITS(Y, n, 1)
.
IF b1 = 1 AND b2 = 1 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
FUNCTION bitNOT RETURNS INTEGER (INPUT X AS INTEGER):
DEFINE VARIABLE b AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
DO n = 1 TO 32:
b = GET-BITS(X, n, 1).
IF b = 0 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
FUNCTION bitOR RETURNS INTEGER (INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
DO n = 1 TO 32:
ASSIGN
b1 = GET-BITS(X, n, 1)
b2 = GET-BITS(Y, n, 1)
.
IF b1 = 1 OR b2 = 1 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
FUNCTION bitShift RETURNS INTEGER (INPUT X AS INTEGER, INPUT S AS INTEGER):
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
ASSIGN
PUT-BITS(Z, 1, s) = GET-BITS(X, 33 - s, s)
PUT-BITS(Z, s + 1, 32 - s) = GET-BITS(X, 1, 32 - s)
.
RETURN Z.
END FUNCTION.
FUNCTION bitXOR RETURNS INTEGER (INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
DO n = 1 TO 32:
ASSIGN
b1 = GET-BITS(X, n, 1)
b2 = GET-BITS(Y, n, 1)
.
IF b1 + b2 = 1 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
/* function to convert integer to hex (starting with low order byte first) */
FUNCTION hexGet RETURNS CHARACTER (INPUT X AS INTEGER):
DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE h AS CHARACTER NO-UNDO INITIAL "0123456789abcdef".
DEFINE VARIABLE Z AS CHARACTER NO-UNDO.
DO n = 0 TO 3:
ASSIGN
b1 = GET-BITS(X, n * 8 + 5, 4)
b2 = GET-BITS(X, n * 8 + 1, 4)
.
Z = Z + SUBSTRING(h, b1 + 1, 1) + SUBSTRING(h, b2 + 1, 1).
END.
RETURN Z.
END FUNCTION.
/* MD5 operations */
FUNCTION F RETURNS INTEGER(INPUT X AS INTEGER, INPUT Y AS INTEGER,
INPUT Z AS INTEGER):
RETURN bitOR(bitAND(X,Y), bitAND(bitNOT(X),Z)).
END FUNCTION.
FUNCTION G RETURNS INTEGER(INPUT X AS INTEGER, INPUT Y AS INTEGER,
INPUT Z AS INTEGER):
RETURN bitOR(bitAND(X, Z), bitAND(Y, bitNOT(Z))).
END FUNCTION.
FUNCTION H RETURNS INTEGER(INPUT X AS INTEGER, INPUT Y AS INTEGER,
INPUT Z AS INTEGER):
RETURN bitXOR(bitXOR(X, Y), Z).
END FUNCTION.
FUNCTION I RETURNS INTEGER(INPUT X AS INTEGER, INPUT Y AS INTEGER,
INPUT Z AS INTEGER):
RETURN bitXOR(Y, bitOR(X, bitNOT(Z))).
END FUNCTION.
/* in the following operations, notice the values for X[k] and T[i]
are passed in rather than looked up--slight deviation from standard */
PROCEDURE Round1:
DEFINE INPUT-OUTPUT PARAMETER a AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER b AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER c AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER d AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Xk AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER s AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Ti AS INTEGER NO-UNDO.
a = b + bitShift(a + F(b, c, d) + Xk + Ti, s).
END PROCEDURE.
PROCEDURE Round2:
DEFINE INPUT-OUTPUT PARAMETER a AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER b AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER c AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER d AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Xk AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER s AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Ti AS INTEGER NO-UNDO.
a = b + bitShift(a + G(b, c, d) + Xk + Ti, s).
END PROCEDURE.
PROCEDURE Round3:
DEFINE INPUT-OUTPUT PARAMETER a AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER b AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER c AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER d AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Xk AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER s AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Ti AS INTEGER NO-UNDO.
a = b + bitShift(a + H(b, c, d) + Xk + Ti, s).
END PROCEDURE.
PROCEDURE Round4:
DEFINE INPUT-OUTPUT PARAMETER a AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER b AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER c AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER d AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Xk AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER s AS INTEGER NO-UNDO.
DEFINE INPUT PARAMETER Ti AS INTEGER NO-UNDO.
a = b + bitShift(a + I(b, c, d) + Xk + Ti, s).
END PROCEDURE.
/* main function to compute an MD5 digest */
FUNCTION MD5 RETURNS CHARACTER (INPUT cMessage AS CHARACTER):
DEFINE VARIABLE A AS INTEGER NO-UNDO.
DEFINE VARIABLE AA AS INTEGER NO-UNDO.
DEFINE VARIABLE B AS INTEGER NO-UNDO.
DEFINE VARIABLE BB AS INTEGER NO-UNDO.
DEFINE VARIABLE C AS INTEGER NO-UNDO.
DEFINE VARIABLE CC AS INTEGER NO-UNDO.
DEFINE VARIABLE D AS INTEGER NO-UNDO.
DEFINE VARIABLE DD AS INTEGER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE M AS MEMPTR NO-UNDO.
DEFINE VARIABLE N AS INTEGER NO-UNDO.
DEFINE VARIABLE X AS INTEGER NO-UNDO EXTENT 16.
DEFINE VARIABLE cDigest AS CHARACTER NO-UNDO.
DEFINE VARIABLE iLenOrig AS INTEGER NO-UNDO.
DEFINE VARIABLE iLenPadded AS INTEGER NO-UNDO.
DEFINE VARIABLE iPadding AS INTEGER NO-UNDO.
/* compute original message length */
iLenOrig = LENGTH(cMessage).
/* compute padded message length:
a) must be a multiple of 64 bytes
b) must have at least 9 bytes of padding
*/
iPadding = 64 - iLenOrig MOD 64.
IF iPadding < 9 THEN iPadding = iPadding + 64.
iLenPadded = iLenOrig + iPadding.
/* create MEMPTR to hold message since we need to manipulate bits,
bytes, and long words */
ASSIGN
SET-SIZE(M) = iLenPadded
SET-BYTE-ORDER(M) = 3 /* little-endian */
.
/* add padding */
ASSIGN
PUT-STRING(M, 1, iLenOrig) = cMessage
PUT-BYTE(M, iLenOrig + 1) = 128
PUT-LONG(M, iLenPadded - 7) = iLenOrig * 8
.
/* initialize MD registers */
ASSIGN
A = 1732584193
B = -271733879
C = -1732584194
D = 271733878
.
/* process message in N blocks of 16 words (64 bytes) */
N = iLenPadded / 64 - 1.
DO i = 0 TO N:
/* copy 16 words into working buffer X */
DO j = 0 TO 15:
X[j + 1] = GET-LONG(M, i * 64 + j * 4 + 1).
END.
/* store current MD5 registers */
ASSIGN
AA = A
BB = B
CC = C
DD = D
.
/* note: in the following rounds, minor changes were made:
a) X[k] is passed rather than k
b) T[i] is passed rather that i
c) because Progress has one based arrays, the subscript
for X[k] is one higher than the standard algorithm
*/
/* round 1 */
RUN Round1(INPUT-OUTPUT A, B, C, D, X[1], 7, -680876936).
RUN Round1(INPUT-OUTPUT D, A, B, C, X[2], 12, -389564586).
RUN Round1(INPUT-OUTPUT C, D, A, B, X[3], 17, 606105819).
RUN Round1(INPUT-OUTPUT B, C, D, A, X[4], 22, -1044525330).
RUN Round1(INPUT-OUTPUT A, B, C, D, X[5], 7, -176418897).
RUN Round1(INPUT-OUTPUT D, A, B, C, X[6], 12, 1200080426).
RUN Round1(INPUT-OUTPUT C, D, A, B, X[7], 17, -1473231341).
RUN Round1(INPUT-OUTPUT B, C, D, A, X[8], 22, -45705983).
RUN Round1(INPUT-OUTPUT A, B, C, D, X[9], 7, 1770035416).
RUN Round1(INPUT-OUTPUT D, A, B, C, X[10], 12, -1958414417).
RUN Round1(INPUT-OUTPUT C, D, A, B, X[11], 17, -42063).
RUN Round1(INPUT-OUTPUT B, C, D, A, X[12], 22, -1990404162).
RUN Round1(INPUT-OUTPUT A, B, C, D, X[13], 7, 1804603682).
RUN Round1(INPUT-OUTPUT D, A, B, C, X[14], 12, -40341101).
RUN Round1(INPUT-OUTPUT C, D, A, B, X[15], 17, -1502002290).
RUN Round1(INPUT-OUTPUT B, C, D, A, X[16], 22, 1236535329).
/* round 2 */
RUN Round2(INPUT-OUTPUT A, B, C, D, X[2], 5, -165796510).
RUN Round2(INPUT-OUTPUT D, A, B, C, X[7], 9, -1069501632).
RUN Round2(INPUT-OUTPUT C, D, A, B, X[12], 14, 643717713).
RUN Round2(INPUT-OUTPUT B, C, D, A, X[1], 20, -373897302).
RUN Round2(INPUT-OUTPUT A, B, C, D, X[6], 5, -701558691).
RUN Round2(INPUT-OUTPUT D, A, B, C, X[11], 9, 38016083).
RUN Round2(INPUT-OUTPUT C, D, A, B, X[16], 14, -660478335).
RUN Round2(INPUT-OUTPUT B, C, D, A, X[5], 20, -405537848).
RUN Round2(INPUT-OUTPUT A, B, C, D, X[10], 5, 568446438).
RUN Round2(INPUT-OUTPUT D, A, B, C, X[15], 9, -1019803690).
RUN Round2(INPUT-OUTPUT C, D, A, B, X[4], 14, -187363961).
RUN Round2(INPUT-OUTPUT B, C, D, A, X[9], 20, 1163531501).
RUN Round2(INPUT-OUTPUT A, B, C, D, X[14], 5, -1444681467).
RUN Round2(INPUT-OUTPUT D, A, B, C, X[3], 9, -51403784).
RUN Round2(INPUT-OUTPUT C, D, A, B, X[8], 14, 1735328473).
RUN Round2(INPUT-OUTPUT B, C, D, A, X[13], 20, -1926607734).
/* round 3 */
RUN Round3(INPUT-OUTPUT A, B, C, D, X[6], 4, -378558).
RUN Round3(INPUT-OUTPUT D, A, B, C, X[9], 11, -2022574463).
RUN Round3(INPUT-OUTPUT C, D, A, B, X[12], 16, 1839030562).
RUN Round3(INPUT-OUTPUT B, C, D, A, X[15], 23, -35309556).
RUN Round3(INPUT-OUTPUT A, B, C, D, X[2], 4, -1530992060).
RUN Round3(INPUT-OUTPUT D, A, B, C, X[5], 11, 1272893353).
RUN Round3(INPUT-OUTPUT C, D, A, B, X[8], 16, -155497632).
RUN Round3(INPUT-OUTPUT B, C, D, A, X[11], 23, -1094730640).
RUN Round3(INPUT-OUTPUT A, B, C, D, X[14], 4, 681279174).
RUN Round3(INPUT-OUTPUT D, A, B, C, X[1], 11, -358537222).
RUN Round3(INPUT-OUTPUT C, D, A, B, X[4], 16, -722521979).
RUN Round3(INPUT-OUTPUT B, C, D, A, X[7], 23, 76029189).
RUN Round3(INPUT-OUTPUT A, B, C, D, X[10], 4, -640364487).
RUN Round3(INPUT-OUTPUT D, A, B, C, X[13], 11, -421815835).
RUN Round3(INPUT-OUTPUT C, D, A, B, X[16], 16, 530742520).
RUN Round3(INPUT-OUTPUT B, C, D, A, X[3], 23, -995338651).
/* round 4 */
RUN Round4(INPUT-OUTPUT A, B, C, D, X[1], 6, -198630844).
RUN Round4(INPUT-OUTPUT D, A, B, C, X[8], 10, 1126891415).
RUN Round4(INPUT-OUTPUT C, D, A, B, X[15], 15, -1416354905).
RUN Round4(INPUT-OUTPUT B, C, D, A, X[6], 21, -57434055).
RUN Round4(INPUT-OUTPUT A, B, C, D, X[13], 6, 1700485571).
RUN Round4(INPUT-OUTPUT D, A, B, C, X[4], 10, -1894986606).
RUN Round4(INPUT-OUTPUT C, D, A, B, X[11], 15, -1051523).
RUN Round4(INPUT-OUTPUT B, C, D, A, X[2], 21, -2054922799).
RUN Round4(INPUT-OUTPUT A, B, C, D, X[9], 6, 1873313359).
RUN Round4(INPUT-OUTPUT D, A, B, C, X[16], 10, - 30611744).
RUN Round4(INPUT-OUTPUT C, D, A, B, X[7], 15, -1560198380).
RUN Round4(INPUT-OUTPUT B, C, D, A, X[14], 21, 1309151649).
RUN Round4(INPUT-OUTPUT A, B, C, D, X[5], 6, -145523070).
RUN Round4(INPUT-OUTPUT D, A, B, C, X[12], 10, -1120210379).
RUN Round4(INPUT-OUTPUT C, D, A, B, X[3], 15, 718787259).
RUN Round4(INPUT-OUTPUT B, C, D, A, X[10], 21, -343485551).
/* update MD5 registers */
ASSIGN
A = A + AA
B = B + BB
C = C + CC
D = D + DD
.
END.
/* convert MD5 registers to hex string from low-order A to high-order D */
cDigest = hexGet(A) + hexGet(B) + hexGet(C) + hexGet(D).
/* cleanup and return */
SET-SIZE(M) = 0.
RETURN cDigest.
END FUNCTION.
&ENDIF
/* End of _md5.i */
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
I try To find a solution to a question ....
we have a number , example : 20 ...
and we have 6 number :{ a ,b , c , d , e , f} < 20 ,
t try to find all values of these numbers , but only if we can combinate (whit + or -) whit 2 of this numbers and getting all the value below to 20 : for example
we choose 31 :
a = 22 b = 21 c = 14 d = 11 e = 9 f = 5
we have :
22 - 21 = 1 ;
11 - 9 = 2 ;
14 - 11 = 3 ;
9 - 5 = 4 ;
f = 5 ;
11 - 5 = 6 ;
21 - 14 = 7 ;
....
....
....
....
....
21 + 9 = 30 ;
9 + 22 = 31 ;
This appears like homework, so I'll try to just give you some hints.
You want to loop over all combinations of two numbers from the array. To do that, you can use an outer loop that loops over all the numbers and then inside that loop, an inner loop that also loops over all the numbers.
Depending on exactly what you want to do, you need to decide if you want to handle x, y separately from y, x
Given a natural number n, find all combinations of 6 positive integers a, b, c, d, e, and f such that {a, b, c, d, e, f} ∪ {a + b, a + c, ..., a + f, b + c, b + d, ..., b + f, ..., e + f} ∪ {a - b, a - c, ..., a - f, b - c, b - d, ..., b - f, ..., e - f, b - a, c - a, ..., f - a, c - b, d - b, ..., f - b, ..., f - e} contains 1, 2, 3, 4, ..., n - 1, and n.
I haven't thought about this problem very much, but it appears to me to be a hard problem, indeed. Maybe there is a trick, I am not sure, but if I had to solve this problem, I would first try to find the least n for which there are not infinitely-many solutions (if n is 1, for example, then any combination of 6 natural numbers containing two consecutive natural numbers will work).
I think that you will have better luck with finding a solution to this problem in a mathematics discussion forum.
void FindCombinations(int n, int [] values)
{
for(int i = 0; i < values.length; i++)
{
int left = values[i];
for(int j = 0; k < values.length; j++)
{
int right = values[j];
if (left == right)
continue;
if (left + right < n)
Console.Write(string.Format("{0} + {1} = {2} < {3}", left, right, left+right, n);
if (left - right < n)
Console.Write(string.Format("{0} - {1} = {2} < {3}", left, right, left-right, n);
}
}
}
While this question stinks of homework it's not really that hard (although arguably hard to interpret).
Note: This solution is O(n^2) and is not efficient, please keep this in mind.