So I have an array of elements, x and y
x = [11; 22; 5; 12; 42; 21; 41; 32; 10; ]
y = [0; 1; 0; 1; 0; 1; 0; 1; 0; ]
Each element position in array x corresponds to array y elements. For example, 11 corresponds to 0, 22 corresponds to 1, 5 corresponds to 0, etc.
I went ahead and created a new array which orders the x array in ascending order:
Now given the new array:
c = [5; 10; 11; 12; 21; 22; 32; 41; 42]
I want to now remake the y array so that the array aligns with the new array c, I am having trouble thinking of a way to do that in a way that is not hard coding. Please help.
You want the second output of sort, which tells you the sorting that was applied to its input, so you can apply it to the other array:
[c, ind] = sort(x);
d = y(ind);
I am trying to implement Array.make of the OCaml Array module. However I'm not getting the values right, my implementation:
let make_diy s v =
let rec aux s v =
if s = 0 then [| |]
else Array.append v ( aux (s-1) v )
in aux s v;;
...has the value: val make_diy : int -> 'a array -> 'a array = <fun>instead of: int -> 'a -> 'a array. It only creates an array if v is already in an array:
make_diy 10 [|3|];;
- : int array = [|3; 3; 3; 3; 3; 3; 3; 3; 3; 3|]
make_diy 10 3;;
Error: This expression has type int but an expression was expected of type
'a array
I also tried to make it with an accumulator, but it has the same result:
let make_diy s v =
let rec aux s v acc =
if s=0 then acc
else append v ( aux (s-1) v acc )
in aux s v [| |];;
EDIT: (typo) append instead of add
The problem seems to be that Array.append expects two arrays. If you want to use it with just an element, you need to wrap the first argument into an array:
Array.append [| v |] (aux (s - 1) v)
Note that this isn't a particularly efficient way to build up an array. Each iteration will allocate a new, slightly larger array. But presumably this is just a learning exercise.
I have three arrays - first is a float array, second is a string array, and third is a float array comprising the sorted, unique values from the first array.
module SOQN =
open System
type collective = { score:double; yes:int; no:int; correct:double }
let first = [| 25; 20; 23; 10; 8; 5; 4; 12; 19; 15; 15; 12; 11; 11 |]
let second = [| "No"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No" |]
let third = Array.distinct (first |> Array.sort)
let fourth = Seq.zip first second
let fifth = fourth |> Seq.sortBy fst
let yesCounts =
fifth
|> Seq.filter (fun (_, y) -> if y = "Yes" then true else false)
|> Seq.map fst
let noCounts =
fifth
|> Seq.filter (fun (_, y) -> if y = "No" then true else false)
|> Seq.map fst
(*
Expected Result:
third = [| 4; 5; 8; 10; 11; 12; 15; 19; 20; 23; 25 |]
yesCounts = [| 1; 1; 2; 3; 4; 4; 6; 7; 7; 8; 8 |]
noCounts = [| 0; 1; 1; 1; 2; 4; 4; 4; 5; 5; 6 |]
yesProportions = [| 1/1; 1/2; ;2/3 3/4; 4/6; 4/8; 6/10; 7/11; 7/12; 8/13; 8/14 |]
*)
I need a new collection generated from iterating through the third array and including the yes and no counts "<=" each of its values. Finally, I need to iterate through this new collection to create a new column comprising the yes proportions at each value and printing each unique value and its matching yes proportion.
Please advise?
First, use some more meaningful names:
let nums = [| 25; 20; 23; 10; 8; 5; 4; 12; 19; 15; 15; 12; 11; 11 |]
let yesNos = // convert string -> bool to simplify following code
[| "No"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No"; "Yes"; "Yes"; "Yes"; "No"; "Yes"; "No" |]
|> Array.map (fun s -> s = "Yes")
let distinctNums = nums |> Array.distinct |> Array.sort
let numYesNos = Array.zip nums yesNos
Then if you really want separate collections for each yes/no/ratio calculation, you can build those using a fold:
let foldYesNos num (yesCounts, noCounts, yesRatios) =
// filter yes/no array by <= comparison
// then partition it into two arrays by the second bool item
let (yays, nays) = numYesNos |> Array.filter (fun (n,_) -> n <= num) |> Array.partition snd
let yesCount = Array.length yays
let noCount = Array.length nays
let yesRatio = float yesCount / float(yesCount + noCount)
(yesCount::yesCounts, noCount::noCounts, yesRatio::yesRatios)
// fold *back* over the distinct numbers
// to make the list accumulation easier/not require a reversal
let (yays, nays, ratio) = Seq.foldBack foldYesNos (distinctNums |> Seq.sort) ([], [], [])
However, I assume since you posted a Collective record type in the sample that you might actually want to emit one of these records for each input:
type Collective = { score:int; yes:int; no:int; correct:float }
let scoreNum num =
let (yays, nays) = numYesNos |> Array.filter (fun (n,_) -> n <= num) |> Array.partition snd
let yesCount = Array.length yays
let noCount = Array.length nays
let yesRatio = float yesCount / float(yesCount + noCount)
{ score = num; yes = yesCount; no = noCount; correct = yesRatio }
distinctNums |> Array.map scoreNum
You can see this code is very similar, it just returns a Collective record for each input rather than building lists for the individual calculations, and so we can use a map instead of a fold.
Suppose I have an array of M elements, all numbers, negative or positive or zero.
Can anyone suggest an algorithm to select N elements from the array, such that the sum of these N elements is the smallest possible positive number?
Take this array for example:
-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200
Now I have to select any 5 elements such that their sum is the smallest possible positive number.
Formulation
For i = 1, ..., M:
Let a_i be the ith number in your list of candidates
Let x_i denote whether the ith number is included in your set of N chosen numbers
Then you want to solve the following integer programming problem.
minimize: sum(a_i * x_i)
with respect to: x_i
subject to:
(1) sum(a_i * x_i) >= 0
(2) sum(x_i) = N
(3) x_i in {0, 1}
You can apply an integer program solver "out of the box" to this problem to find the optimal solution or a suboptimal solution with controllable precision.
Resources
Integer programming
Explanation of branch-and-bound integer program solver
If you want to find the best possible solution, you can simply use brute force ie. try all posible combinations of fiwe numbers.
Something like this very quick and dirty algorithm:
public List<Integer> findLeastPositivSum(List<Integer> numbers) {
List<Integer> result;
Integer resultSum;
List<Integer> subresult, subresult2, subresult3, subresult4, subresult5;
for (int i = 0; i < numbers.size() - 4; i++) {
subresult = new ArrayList<Integer>();
subresult.add(numbers.get(i));
for (int j = i + 1; j < numbers.size() - 3; j++) {
subresult2 = new ArrayList<Integer>(subresult);
subresult2.add(j);
for (int k = j + 1; k < numbers.size() - 2; k++) {
subresult3 = new ArrayList<Integer>(subresult2);
subresult3.add(k);
for (int l = k + 1; l < numbers.size() - 1; l++) {
subresult4 = new ArrayList<Integer>(subresult3);
subresult4.add(k);
for (int m = l + 1; m < numbers.size(); m++) {
subresult5 = new ArrayList<Integer>(subresult4);
subresult5.add(k);
Integer subresultSum = sum(subresult5);
if (subresultSum > 0) {
if (result == null || resultSum > subresultSum) {
result = subresult;
}
}
}
}
}
}
}
return result;
}
public Integer sum(List<Integer> list) {
Integer result = 0;
for (Integer integer : list) {
result += integer;
}
return result;
}
This is really quick and dirty algorithm, it can be done more elegantly. I can provide cleaner algorithm e.g. using recursion.
It can be also further optimized. E.g. you can remove similar numbers from input list as first step.
Let initial array be shorted already, or i guess this will work even when it isnt shorted..
N -> Length of array
M -> Element req.
R[] -> Answer
TEMP[] -> For calculations
minSum -> minSum
A[] -> Initial input
All above variables are globally defined
int find(int A[],int start,int left)
{
if(left=0)
{
//sum elements in TEMP[] and save it as curSum
if(curSum<minSum)
{
minSum=curSum;
//assign elements from TEMP[] to R[] (i.e. our answer)
}
}
for(i=start;i<=(N-left);i++)
{
if(left==M)
curSum=0;
TEMP[left-1]=A[i];
find(A[],i+1,left-1);
}
}
// Made it in hurry so maybe some error would be existing..
Working solution on ideone :
http://ideone.com/YN8PeW
I suppose Kadane’s Algorithm would do the trick, although it is for the maximum sum but I have also implemented it to find the minimum sum, though can't find the code right now.
Here's something sub optimal in Haskell, which (as with many of my ideas) could probably be further and better optimized. It goes something like this:
Sort the array (I got interesting results by trying both ascending and descending)
B N = first N elements of the array
B (i), for i > N = best candidate; where (assuming integers) if they are both less than 1, the candidates are compared by the absolute value of their sums; if they are both 1 or greater, by their sums; and if only one candidate is greater than 0 then that candidate is chosen. If a candidate's sum is 1, return that candidate as the answer. The candidates are:
B (i-1), B (i-1)[2,3,4..N] ++ array [i], B (i-1)[1,3,4..N] ++ array [i]...B (i-1)[1,2..N-1] ++ array [i]
B (i-2)[2,3,4..N] ++ array [i], B (i-2)[1,3,4..N] ++ array [i]...B (i-2)[1,2..N-1] ++ array [i]
...
B (N)[2,3,4..N] ++ array [i], B (N)[1,3,4..N] ++ array [i]...B (N)[1,2..N-1] ++ array [i]
Note that for the part of the array where the numbers are negative (in the case of ascending sort) or positive (in the case of descending sort), step 3 can be done immediately without calculations.
Output:
*Main> least 5 "desc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(10,[-1000,600,300,100,10])
(0.02 secs, 1106836 bytes)
*Main> least 5 "asc" [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
(50,[300,100,-200,-100,-50])
(0.02 secs, 1097492 bytes)
*Main> main -- 10000 random numbers ranging from -100000 to 100000
(1,[-106,4,-40,74,69])
(1.77 secs, 108964888 bytes)
Code:
import Data.Map (fromList, insert, (!))
import Data.List (minimumBy,tails,sort)
import Control.Monad.Random hiding (fromList)
array = [-1000,-700,-400,-200,-100,-50,10,100,300,600,800,1200]
least n rev arr = comb (fromList listStart) [fst (last listStart) + 1..m]
where
m = length arr
r = if rev == "asc" then False else True
sorted = (if r then reverse else id) (sort arr)
listStart = if null lStart
then [(n,(sum $ take n sorted,take n sorted))]
else lStart
lStart = zip [n..]
. takeWhile (all (if r then (>0) else (<0)) . snd)
. foldr (\a b -> let c = take n (drop a sorted) in (sum c,c) : b) []
$ [0..]
s = fromList (zip [1..] sorted)
comb list [] = list ! m
comb list (i:is)
| fst (list ! (i-1)) == 1 = list ! (i-1)
| otherwise = comb updatedMap is
where updatedMap = insert i bestCandidate list
bestCandidate = comb' (list!(i - 1)) [i - 1,i - 2..n] where
comb' best [] = best
comb' best (j:js)
| fst best == 1 = best
| otherwise =
let s' = map (\x -> (sum x,x))
. (take n . map (take (n - 1)) . tails . cycle)
$ snd (list!j)
t = s!i
candidate = minimumBy compare' (map (add t) s')
in comb' (minimumBy compare' [candidate,best]) js
add x y#(a,b) = (x + a,x:b)
compare' a#(a',_) b#(b',_)
| a' < 1 = if b' < 1 then compare (abs a') (abs b') else GT
| otherwise = if b' < 1 then LT else compare a' b'
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (-100000,100000)
main = do
values <- evalRandIO (sequence (replicate (10000) rnd))
putStrLn (show $ least 5 "desc" values)
Assumption: M is the original array
Pesudocode
S = sort(M);
R = [];
sum = 0;
for(i=0, i < length(S); i++){
sum = sum + S[i];
if(sum < 1){
R.push(S[i]);
}else{
return R;
}
}
I know how to simulate a 2d array in a linear array using [x + y * width] as a linear index.
I can extend this to 3d arrays: [x + y * width + z * width * height].
Is there a general formula for N-dimensional array?
I'm looking for a language-agnostic answer.
Sure. Just extending your example gives x + y*width + z*width*height + w*width*height*depth + ...
In other words, dim1 + dim2*size1 + dim3*size1*size2 + dim4*size1*size2*size3 + ...
Eh, if you want some code... :-) C is language-agnostic enough, ya?
Assume input: location[dimensions]
Assume a table exists maxBound[dimensions] that contains the maximum boundaries of each dimension of the table.
int index = 0;
int multiplier = 1;
for (int i = 0;i < dimensions;i++)
{
index += location[i] * multiplier;
multiplier *= maxBound[i];
}
Your index will end up in the index field.
Test:
location = [3,4,5]
maxBound = [10,20,30]
loop initial: index = 0, multiplier = 1.
loop i=0: index = 3, multiplier = 10.
loop i=1: index = 43, multiplier = 200.
loop i=2: index = 1043, multipler = 6000.
I think this makes sense, but this is just coming out of the top of my head.