I'm working on a project which requires me to partition a list using a list. I've created a solution which works in some situations, but not every situation. Is anyone able to help me with the logic?
There's two lists. The sum of each list will always be equal. The first list (i.e. the partitionBy list) is used to partition the second list (i.e the inputList).
Here's a simplified example:
List A {3, 2, 4}
List B {2, 1, 1, 1, 3, 1}
The first item of List A is 3. The sum of the first and second items of List B = 3 (i.e 2 + 1). Create a list for those items
The second item of List A is 2. The sum of the third and fourth items of List B = 2 (i.e. 1 + 1). Create a list for those items
etc ...
Ideal result would be: {{2, 1}, {1, 1}, {3, 1}}
The code is currently in AppleScript, but I'd be happy to translate it to JavaScript, if that helps.
Here's the code w/ examples:
--Example 1 works as expected
set partitionBy1 to {4, 1, 9, 6, 2, 2} -- list to partition by
set inputList1 to {1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 1} -- list to partition
-- required output: {{1, 1, 1, 1}, {1}, {2, 2, 2, 3}, {3, 3}, {1, 1}, {1, 1}}
-- actual output: {{1, 1, 1, 1}, {1}, {2, 2, 2, 3}, {3, 3}, {1, 1}, {1, 1}}
--Example 2 works as expected
set partitionBy2 to {4, 2, 8, 6, 2, 2}
set inputList2 to {1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 1, 1, 1}
-- required output: {{1, 1, 1, 1}, {1, 1}, {1, 2, 2, 3}, {3, 3}, {1, 1}, {1, 1}}
-- actual output: {{1, 1, 1, 1}, {1, 1}, {1, 2, 2, 3}, {3, 3}, {1, 1}, {1, 1}}
--Example 3 does not work as expected
set partitionBy3 to {4, 1, 9, 1, 3, 6, 2, 2}
set inputList3 to {1, 1, 1, 1, 1, 2, 2, 2, 3, 4, 3, 3, 1, 1, 1, 1}
-- required output: {{1, 1, 1, 1}, {1}, {2, 2, 2, 3}, {1}, {3}, {3, 3}, {1, 1}, {1, 1}}
-- actual output: {{1, 1, 1, 1}, {1}, {2, 2, 2, 3}, {3}, {3}, {3, 3}, {1, 1}, {1, 1}}
partitionList(inputList3, partitionBy3)
on partitionList(inputList, partitionBy)
set partitionedList to {}
repeat with i from 1 to (count partitionBy)
set partitionNumber to item i of partitionBy
set runningTotal to 0
set intermediateList to {}
repeat with j from 1 to ((count inputList) - 1)
set inputNumber to item j of inputList
set runningTotal to runningTotal + inputNumber
if runningTotal = partitionNumber then
set end of partitionedList to (intermediateList & inputNumber)
set inputList to items (j + 1) thru -1 of inputList
exit repeat
else if runningTotal > partitionNumber then
set item j of inputList to (inputNumber - 1)
set inputList to (inputNumber - 1) & inputList
set end of partitionedList to (intermediateList & (inputNumber - 1))
set inputList to items (j + 1) thru -1 of inputList
exit repeat
else
set end of intermediateList to inputNumber
end if
end repeat
end repeat
set end of partitionedList to intermediateList & item -1 of inputList
return partitionedList
end partitionList
The problem is the linear incrementation of j.
In case of runningTotal > partitionNumber you have to assign the difference (or the remainder) to inputNumber and evaluate the next partition without incrementing j.
I replaced repeat with with repeat while, added an overflow variable to indicate that runningTotal is greater than partitionNumber and declared j as local variable to have full control.
on partitionList(inputList, partitionBy)
set partitionedList to {}
set j to 1
set overflow to false
repeat with i from 1 to (count partitionBy)
set partitionNumber to item i of partitionBy
set runningTotal to 0
set intermediateList to {}
repeat while j < (count inputList)
if overflow then
set overflow to false
else
set inputNumber to item j of inputList
end if
set runningTotal to runningTotal + inputNumber
if runningTotal = partitionNumber then
set end of partitionedList to (intermediateList & inputNumber)
set j to j + 1
exit repeat
else if runningTotal > partitionNumber then
set end of partitionedList to {partitionNumber}
set overflow to true
set inputNumber to runningTotal - partitionNumber
exit repeat
else
set end of intermediateList to inputNumber
set j to j + 1
end if
end repeat
end repeat
set end of partitionedList to intermediateList & item -1 of inputList
return partitionedList
end partitionList
Related
I'm stuck here, and can't generate a do loop that repeats this operation 10k times and result in a list or array
{((RandomVariate[TruncatedDistribution[{0, 1}, NormalDistribution[]],
12])) - 0.5}
Do does things but it doesn't generate output. E.g.
Do[{1, 2, 3}, 2]
- no output -
Have it add to a list though...
alist = {};
Do[alist = Join[alist, {1, 2, 3}], 2]
alist
{1, 2, 3, 1, 2, 3}
I would like to eliminate the third element of every list within a nested list.
E.g.,
lst = { {1, 0, 0}, {1, 1, 1}, {1, 1, 4} }
So it would become
{ {1, 0}, {1, 1}, {1, 1} }
How should I do that?
yet another:
lst = #[[1;;2]] & /# lst
or if you want to drop only the third element from possibly longer sublists:
lst = Drop[#,{3}]& /# lst
Lots of way to do that, e.g.
lst = {{1, 0, 0}, {1, 1, 1}, {1, 1, 4}};
lst = lst[[All, {1, 2}]]
{{1, 0}, {1, 1}, {1, 1}}
Or
lst = Transpose[Most[Transpose[lst]]]
Or, without transposing
lst = MapThread[Delete, {lst, Table[3, {Length[lst]}]}]
let n be an integer and A = {2,3,...,10} and I want to do as follows:
divide n to 2, so there is a reminder r2 and a quotient q2.
divide q2 to 3, so there is a reminder r3 and a quotient q3.
we repeat this until the quotient is less than the next number.
write together the last quotient with the previous reminders.
For example n=45
45/2 ....... r_2=1, q_2=22
22/3 ....... r_3=1, q_3=7
7/4 ....... r_4=3, q_4=1
since q4 = 1 is less than the next number i.e. 5, we break.
the result is q4r4r3r2 where it is equal to 1311.
Thank you for your help.
I did this but it does not work
n = 45;
i = 2;
list = {Mod[n, i]};
While[Quotient[n, i] >= i + 1, n == Quotient[n, i]; i++;
AppendTo[list, Mod[n, i]];
If[Quotient[n, i] < i + 1, Break[]]; AppendTo[list, Quotient[n, i]]];
list
Row[Reverse[list]]
which gives
{1, 0, 15, 1, 11, 0, 9, 3, 7, 3}
Row[{3, 7, 3, 9, 0, 11, 1, 15, 0, 1}]
where it is not my desired result.
This is the code:
A = Table[i, {i, 2, 10}]; (* array of numbers *)
n = 45; (* initial value *)
ans = {}; (* future answer which is now empty list *)
For[i = 1, i <= Length[A], i++, (* looping over A *)
If[n < A[[i]], (* exit condition *)
ans = Append[ans, n]; (* appending last n when exit *)
Break[]
];
qr = QuotientRemainder[n, A[[i]]]; (* calculating both quotient and reminder *)
ans = Append[ans, qr[[2]]]; (* adding second member to the answer *)
Print[qr]; (* printing *)
n = qr[[1]]; (* using first member as new n to process *)
];
ans (* printing result in Mathematica manner *)
It gives
{1, 1, 3, 1}
You might use something like this:
f[n_Integer] :=
NestWhileList[
{QuotientRemainder[#[[1, 1]], #[[2]] + 1], #[[2]] + 1} &,
{{n}, 1},
#[[1, 1]] != 0 &
] // Rest
f[45]
{{{22, 1}, 2}, {{7, 1}, 3}, {{1, 3}, 4}, {{0, 1}, 5}}
You can use Part to get whatever bits of the output you desire.
Here's a somewhat more advanced way if you can handle the syntax:
f2[n_Integer] := Reap[f2[{n, 0}, 2]][[2, 1, 2 ;;]] // Reverse
f2[{q_, r_}, i_] := f2[Sow # r; QuotientRemainder[q, i], i + 1]
f2[{0, r_}, i_] := Sow # r
f2[45]
{1, 3, 1, 1}
This is another simple 'matrix' question in Mathematica. I want to show how I did this, and ask if there is a better answer.
I want to select all 'rows' from matrix based on value in the first column (or any column, I used first column here just as an example).
Say, find all rows where the entry in the first position is <=4 in this example:
list = {{1, 2, 3},
{4, 5, 8},
{7 , 8, 9}}
So, the result should be
{{1,2,3},
{4,5,8}}
Well, the problem is I need to use Position, since the result returned by Position can be used directly by Extract. (but can't be used by Part or [[ ]], so that is why I am just looking at Position[] ).
But I do not know how to tell Position to please restrict the 'search' pattern to only the 'first' column so I can do this in one line.
When I type
pos = Position[list, _?(# <= 4 &)]
it returns position of ALL entries which are <=4.
{{1, 1}, {1, 2}, {1, 3}, {2, 1}}
If I first get the first column, then apply Position on it, it works ofcourse
list = {{1, 2, 3},
{4, 5, 8},
{7 , 8, 9}};
pos = Position[list[[All, 1]], _?(# <= 4 &)]
Extract[list, pos]
--> {{1, 2, 3}, {4, 5, 8}}
Also I tried this:
pos = Position[list, _?(# <= 4 &)];
pos = Select[pos, #[[2]] == 1 &] (*only look at ones in the 'first' column*)
{{1, 1}, {2, 1}}--->
and this gives me the correct positions in the first column. To use that to find all rows, I did
pos = pos[[All, 1]] (* to get list of row positions*)
---> {1, 2}
list[[ pos[[1]] ;; pos[[-1]], All]]
{{1, 2, 3},
{4, 5, 8}}
So, to summarize, putting it all together, this is what I did:
method 1
list = {{1, 2, 3},
{4, 5, 8},
{7 , 8, 9}};
pos = Position[list[[All, 1]], _?(# <= 4 &)]
Extract[list, pos]
--> {{1, 2, 3}, {4, 5, 8}}
method 2
list = {{1, 2, 3},
{4, 5, 8},
{7 , 8, 9}}
pos = Position[list, _?(# <= 4 &)];
pos = Select[pos, #[[2]] == 1 &];
pos = pos[[All, 1]];
list[[ pos[[1]] ;; pos[[-1]], All]]
{{1, 2, 3},
{4, 5, 8}}
The above clearly is not too good.
Is method 1 above the 'correct' functional way to do this?
For reference, this is how I do the above in Matlab:
EDU>> A=[1 2 3;4 5 8;7 8 9]
A =
1 2 3
4 5 8
7 8 9
EDU>> A( A(:,1)<=4 , :)
1 2 3
4 5 8
I am trying to improve my 'functional' handling of working with matrices in Mathematica commands, this is an area I feel I am not good at working with lists. I find working with matrices easier for me.
The question is: Is there is a shorter/more functional way to do this in Mathematica?
thanks
You could use Pick[] as follows:
Pick[list, list[[All, 1]], _?(# <= 4 &)]
How about the following?
In[1]:= list = {{1, 2, 3}, {4, 5, 8}, {7, 8, 9}};
In[2]:= Select[list, First[#] <= 4 &]
Out[2]= {{1, 2, 3}, {4, 5, 8}}
Here's a loose translation of your matlab code:
list[[Flatten[Position[Thread[list[[All, 1]] <= 4], True]]]]
(of course, the Flatten would not be needed if I used Extract instead of Part).
There is a faster method than those already presented, using SparseArray. It is:
list ~Extract~
SparseArray[UnitStep[4 - list[[All, 1]]]]["NonzeroPositions"]
Here are speed comparisons with the other methods. I had to modify WReach's method to handle other position specifications.
f1[list_, x_] := Cases[list, {Sequence ## Table[_, {x - 1}], n_, ___} /; n <= 4]
f2[list_, x_] := Select[list, #[[x]] <= 4 &]
f3[list_, x_] := Pick[list, (#[[x]] <= 4 &) /# list]
f4[list_, x_] := Pick[list, UnitStep[4 - list[[All, x]]], 1]
f5[list_, x_] := Pick[list, Thread[list[[All, x]] <= 4]]
f6[list_, x_] := list ~Extract~
SparseArray[UnitStep[4 - list[[All, x]]]]["NonzeroPositions"]
For a table with few rows and many columns (comparing position 7):
a = RandomInteger[99, {250, 150000}];
timeAvg[#[a, 7]] & /# {f1, f2, f3, f4, f5, f6} // Column
0.02248
0.0262
0.312
0.312
0.2808
0.0009728
For a table with few columns and many rows (comparing position 7):
a = RandomInteger[99, {150000, 12}];
timeAvg[#[a, 7]] & /# {f1, f2, f3, f4, f5, f6} // Column
0.0968
0.1434
0.184
0.0474
0.103
0.002872
If you want the rows that meet the criteria, use Cases:
Cases[list, {n_, __} /; n <= 4]
(* {{1, 2, 3}, {4, 5, 8}} *)
If you want the positions within the list rather than the rows themselves, use Position instead of Cases (restricted to the first level only):
Position[list, {n_, __} /; n <= 4, {1}]
(* {{1}, {2}} *)
If you want to be very clever:
Pick[list, UnitStep[4 - list[[All, 1]]], 1]
This also avoids unpacking, which means it'll be faster and use less memory.
I use the following function to perform a conditional operation on a List:
consider[data_, conditionCOL_, conditionVAL_, listOfCol_] :=
Select[data, (#[[conditionCOL]] == conditionVAL) &][[All, listOfCol]]
Considering the following example :
dalist = Join[Tuples[Range[4], 2]\[Transpose], {Range[16], Range[17, 32, 1]}
]\[Transpose];
I use the following to obtain the means of specific columns defined by the function.
This will output the means of entries of column 3 & 4 for which the corresponding entry in column 1 equals 2
Mean#consider[dalist, 1, 2, {3, 4}]
Now, I would like to add constraints/thresholds on the values to be averaged :
Average the values when they are:
Above minValue (e.g., 3)
Under maxValue (e.g., 25)
Below, an example is given of values the average value of which should be calculated under the above mentioned constraints.
Since it is not clear whether you want just to exclude the points outside of the limits from the averaging, or to decide whether or not to perform the averaging, I will address both questions. You can use the following functions to postprocess the results of your consider function (they are rather specific, based on your data format):
filter[data : {{_, _} ..}, {min_, max_}] :=
Select[data, min < #[[1]] < max && min < #[[2]] < max &]
dataWithinLimitsQ[data : {{_, _} ..}, {min_, max_}] :=
data == filter[data, {min, max}]
meanFiltered[data : {{_, _} ..}, {min_, max_}] :=
Mean#filter[data, {min, max}]
Here is how you can use them:
In[365]:= dalist=Join[Tuples[Range[4],2]\[Transpose],{Range[16],Range[17,32,1]}]\[Transpose]
Out[365]= {{1,1,1,17},{1,2,2,18},{1,3,3,19},{1,4,4,20},{2,1,5,21},{2,2,6,22},{2,3,7,23},
{2,4,8,24},{3,1,9,25},{3,2,10,26},{3,3,11,27},{3,4,12,28},{4,1,13,29},{4,2,14,30},{4,3,15,31},
{4,4,16,32}}
In[378]:= considered = consider[dalist,1,1,{3,4}]
Out[378]= {{1,17},{2,18},{3,19},{4,20}}
In[379]:= filter[considered,{2,21}]
Out[379]= {{3,19},{4,20}}
In[380]:= dataWithinLimitsQ[considered,{2,21}]
Out[380]= False
In[381]:= meanFiltered[considered,{2,21}]
Out[381]= {7/2,39/2}
I would use Cases:
inRange[data_, {min_, max_}] := Cases[data, {__?(min < # < max &)}, 1]
This form also accepts data with an arbitrary number of columns.
dat = {{1, 2, 0}, {6, 7, 4}, {6, 7, 7}, {4, 5, 6}, {4, 5, 3}, {9, 7, 1}, {0, 3, 7}, {6, 2, 1}}
inRange[dat, {2, 7}]
(* Out = {{4, 5, 6}, {4, 5, 3}} *)