Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I wrote this Matlab code to generate a vector of random [1 0] and [2 0]:
nTrials = 8;
Seq1 = [1 0]; % sequence 1
Seq2 = [2 0]; % sequence 2
a=repmat(Seq1,(nTrials/4),1);
b=repmat(Seq2,(nTrials/4),1);
abcd = vertcat(a,b); % concatenate all three couples
CouplesOrderStruct = abcd(randperm(size(abcd,1)),:); % couples in columns
vector = (reshape(CouplesOrderStruct.',[],1))';
The result is a vector like: [1 0 2 0 2 0 1 0]
Code explained:
I have two sequences of numbers, 1-0 and 2-0, which I want to randomize in my vector.
First, in a = repmat(Seq1,(nTrials/4),1); b=repmat(Seq2,(nTrials/4),1); I create a fixed amount of sequences
Second, I put a and b together: abcd = vertcat(a,b); % concatenate all three couples
Third, I randomize these sequences in CouplesOrderStruct = abcd(randperm(size(abcd,1)),:);
The results is a vector with the same amount of 1-0 and 2-0, but in a random order
Is there a way to get the same result with JavaScript?
Sooo i just built a nice tiny documented function for you:
function randomRepeatSequence(sequences, times) {
// times has to be a multiple of sequences.length
if (times % sequences.length !== 0)
return console.log("times has to be a multiple of sequences.length");
// Remap our sequence-array so we can store the count it has been used
var seqmap = [];
for (var seqid = 0; seqid < sequences.length; seqid++)
// Push the current sequence n times; n = times/sequences.length
for (var idx = 0; idx < times/sequences.length; idx++)
seqmap.push(sequences[seqid]);
var resultmap = [];
// Now just select and remove a random sequence from our seqmap, until it is empty
while (!seqmap.length == 0) {
// Select a random element
var randomidx = Math.floor(Math.random()*seqmap.length);
var currentElement = seqmap[randomidx];
// remove the random element from seqmap...
seqmap.splice(randomidx, 1);
// .. and push it to the resultmap
resultmap.push(currentElement);
}
// now our resultmap looks like [[1],[2],[3]]... just flatten it!
var result = resultmap.reduce( function(a, b) {
return a.concat(b);
});
return result;
}
You can use it just like
console.log(randomRepeatSequence([[1,0], [2,0]], 4));
Or, better to understand:
var seqlist = [
[1, 0],
[2, 0]
]
randomRepeatSequence(seqlist, 4)
Please care, the times parameter just takes the amount of sequences that have to be used, not the length of the result. But you just have to calculate that in a easy step like
randomRepeatSequence(seqlist, 8/seqlist[0].length)
(giving 4, because seqlist[0].length = 2 and 8 / 2 is 4)
Original Answer
Your result is for example
vector = 2 0 1 0 2 0 1 0
I guess seq1 and seq2 should be contained equal times.
I decided to use an easy-to-understand-approach, even through I can do shorter:
var trials = 8; // has to be even
var seq1 = [1, 0];
var seq2 = [2, 0];
// "Build" a sequence list
var seqlist = [
seq1, seq1,
seq2, seq2
]
var list = []
for (var n = 0; n < trials/2; n++) {
// search a random entry
var index = Math.floor(Math.random()*seqlist.length);
var toUseSeq = seqlist[index];
// delete the entry
seqlist.splice(index, 1);
list.push(toUseSeq);
}
// flatten result array
var result = list.reduce( function(a, b) {
return a.concat(b);
});
console.log(result);
Executing this gaves me one of these console outputs:
[ 2, 0, 1, 0, 2, 0, 1, 0 ]
[ 2, 0, 1, 0, 2, 0, 1, 0 ]
[ 1, 0, 1, 0, 2, 0, 2, 0 ]
[ 1, 0, 2, 0, 1, 0, 2, 0 ]
Related
I have an algo exercise to do and I have no idea how to do it, as the requirement is to use only basic programming concepts. So - the point is to find the longest sequence of numbers in an array that are growing or not changing value.
So for the array [1,1,2,4,0,1,7,4], it would be [1,1,2,4].
It should have as small time and memory complexity as possible. Any solutions, tips? Much love and thanks in advance for any advice or feedback.
That's what I've managed to do in the last 10 minutes, but I feel like I'm doing it in the most complex way possible...
function idk(array) {
var current = 0;
var winner = 0;
var currentArray = [];
var winnerArray = [];
for (let i = 0; i <= array.length; i++) {
if (array[i + 1] >= array[i]) {
currentArray.push(array[i]);
current = currentArray.length;
} else {
currentArray.push(array[i]);
if (currentArray.length > best.length) {
// copy array and append it to the new array?
}
}
}
return winnerArray;
}
Try this javascript algorithm:
var array = [1, 8, 1, 1, 5, 7, 2, 2]
var output = []
array.forEach(function(value, index) {
if (array[index - 1] <= value && index != 0) {
output[output.length - 1].push(value)
} else {
output.push([value])
}
})
var longestArray = []
output.forEach(function(arrayCompare, index) {
if (arrayCompare.length > longestArray.length || index == 0) {
longestArray = arrayCompare
}
})
console.log(longestArray)
The first forEach loops through the elements of array. If the element is larger than or equal to the previous element, it adds it to the last array in output. If it is not, then it creates a new array, and pushes the array into output. This creates arrays with "growing" sequences.
After that, it loops through each sequence, and checks if the length of the sequence is greater than the current longest sequence, which is stored in longestArray. If it is, it changes longestArray to that. If it isn't, it does nothing.
Note that both of these loops have exceptions if the index is 0, since there is no element with index -1 (therefore such an exception had to be made).
Also, here's the same implementation in python:
array = [1, 8, 1, 1, 5, 7, 2, 2]
output = []
index = 0
while index < len(array):
value = array[index]
if (array[index-1] <= value and index !=0):
output[-1].append(value)
else:
output.append([value])
index += 1
longestArray = []
index = 0
while index < len(output):
arrayCompare = output[index]
if index==0 or len(arrayCompare) > len(longestArray):
longestArray = arrayCompare
index += 1
print(longestArray)
Just why loop over the end of the array?
Because you could take this advantage to gather the last longest sequence without having a check after the loop for having found a longest sequence.
But in parts:
Why not a temporary array? Because there is no need to use it, if you collect the values. the startignn index of a sequence is important and the actual indec to decide if the sequence is longer then the previously found one.
The loop feature two conditions, one for continuing the loop, if in sequence and another to check if the actual ended sequence is longer. And for storing the actual index.
The last loop with a check for an undefined value is false, it does not continue the loop and the nect check reveals either a new longest sequence or not.
Some other annotation:
winnerArray has to be an empty array, because of the check later for length
The sequence check take the previous element, because the loop starts with the first index and the previous element is given.
The Big O is O(n).
function idk(array) {
let winnerArray = [],
index = 0;
for (let i = 1; i < array.length + 1; i++) {
if (array[i - 1] <= array[i]) continue;
if (i - index > winnerArray.length) winnerArray = array.slice(index, i);
index = i;
}
return winnerArray;
}
console.log(...idk([1, 1, 2, 4, 0, 1, 7, 4])); // [1, 1, 2, 4]
console.log(...idk([1, 8, 1, 1, 5, 7, 2, 2])); // [1, 1, 5, 7]
console.log(...idk([1, 8, 1, 1, 5, 7, 2, 2, 2, 2, 2]));
Here is the dynamic programming algorithm in Python:
def longest_sequence(numbers):
length = len(numbers)
L = [0] * length #L stores max possible lengths at each index
L[-1] = 1 # base case
for i in range(length-2, -1, -1):
max_length = L[i]
for j in range(i, length):
if (L[j] > max_length) and (numbers[j] > numbers[i]):
max_length = L[j]
L[i] = max_length + 1
#trace back
max_length = max(L)
result = []
for k in range(max_length, 0, -1):
result.append(numbers[L.index(k)])
numbers = numbers[L.index(k):]
L = L[L.index(k):]
return result
my_numbers = [36,13,78,85,16,52,58,61,63,83,46,19,85,1,58,71,26,26,21,31]
print(longest_sequence(my_numbers))
#>>[13, 16, 52, 58, 61, 63, 83, 85]
To be optimal, you should not use intermediate lists during processing. You only need to hold indexes, sizes and the previous value:
def longSeq(A):
longStart,longSize = 0,0 # best range so far (index and size only)
start,size,prev = 0,0,None # current range (index and size)
for i,a in enumerate(A):
if i == 0 or prev <= a: # increase current range
size += 1
prev = a
if size > longSize: # track longest so far
longStart,longSize = start,size
else:
start,size,prev = i,1,a # sequence break, restart current
return A[longStart:longStart+longSize]
output:
print(longSeq([1,1,2,4,0,1,7,4])) # [1, 1, 2, 4]
print(longSeq( [1,8,1,1,5,7,2,2])) # [1, 1, 5, 7]
This will perform in O(n) time and use O(1) space.
I'm trying to solve this question on LeetCode:
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.
Note: The number of elements initialized in nums1 and nums2 are m and n respectively.
You may assume that nums1 has enough space (size that is equal to m + n) to hold additional elements from nums2.
I ended up with coming up with this code:
var merge = function(nums1, m, nums2, n) {
var nums = [];
nums1.length = m;
nums2.length = n;
nums = nums.concat(nums1);
console.log(nums);
nums = nums.concat(nums2);
console.log(nums);
nums = nums.sort();
console.log(nums);
return nums;
}
This is what the 'run code' says:
Your input
[1,2,3,0,0,0]
3
[2,5,6]
3
stdout
[ 1, 2, 3 ]
[ 1, 2, 3, 2, 5, 6 ]
[ 1, 2, 2, 3, 5, 6 ]
Output:
[1,2,3]
Expected
[1,2,2,3,5,6]
(an image version if the quotes weren't clear)
When I'm console.logging the array, the answer is correct but for some reason returning the array gives a completely different output
Can anyone help in this?
I think the hint here is that nums1 is big enough to hold n+m values. So the way to solve this problem is to work backwards through both arrays, filling the empty space in nums1 as you go. So for example, for the first iteration of the loop, you would compare nums1[n-1] and nums2[m-1] and put whichever is larger into nums1[n+m-1]. You then continue this for as long as you have values in either array, copying exclusively from the other if one runs out:
const merge = function(nums1, m, nums2, n) {
n--; m--;
for (let i = m + n + 1; i >= 0; i--) {
nums1[i] = (m < 0 || n >= 0 && nums2[n] > nums1[m]) ? nums2[n--] : nums1[m--];
}
return nums1;
}
console.log(merge([1, 2, 3, 0, 0, 0], 3, [2, 5, 6], 3));
This code is O(n) (as compared to your sort which is O(nlogn)) and requires no additional space.
This question already has answers here:
How to split a long array into smaller arrays, with JavaScript
(26 answers)
Split array into chunks
(73 answers)
Closed 4 years ago.
I am trying to split an array of objects into sets of 3 and there is a slight problem. I run the code and it splits the first group into 2 and the rest into 3. I want the last group to have the remaining elements. So for instance if there are 21 objects then the last group should have 2 but instead the first group is the one with 2. How can I make the last group be the one with the remaining objects?
var newData = [];
var setOfThree = [];
for (i = 0; i < data.length; i++) {
setOfThree.push(data[i]);
if (i % 3 == 1) {
newData.push(setOfThree);
setOfThree = [];
}
}
So the data ends up looking like this:
Here's a very clean and efficient solution (leverages the fact that Array.prototype.slice automatically truncates results):
let groupByN = (n, data) => {
let result = [];
for (let i = 0; i < data.length; i += n) result.push(data.slice(i, i + n));
return result;
};
console.log(JSON.stringify(groupByN(3, [ 1 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6, 7 ])));
console.log(JSON.stringify(groupByN(3, [ 1, 2, 3, 4, 5, 6, 7, 8 ])));
The first array gets 2 items because, when i === 1 1%3 will result to 1
Starting from counter 1 could be one solution
data = [1,2,3,4,5,6,7]
var newData = [];
// var setOfThree = []; // not required
var j = 0
newData.push([]);
//pushing at the very begining, this way we won't miss if the data
// is not in groups of 3
for (i = 1; i <= data.length; i++) {
// always updating the final array
newData[j].push(data[i-1]);
if (i % 3 == 0) {
newData.push([]);
j++;
}
}
if (newData[0].length === 0) {
// if the data you received was epmty
newData.pop()
}
console.log(newData)
Here a recursive implementation, with some es6 sugar
var input = [1,2,3,4,5,6,7,8]
function groupByThree([a,b,c,...rest]){
if (rest.length === 0) return [[a,b,c].filter(x => x!==undefined)]
return [[a,b,c]].concat(groupByThree(rest))
}
console.log(groupByThree(input))
I couldn't find the simple and readable way to solve it.
the operations on single element array like [6] in javascript is horrible...
Question
originArray is a sorted, non-overlapping array.
and input is always a single positive integer.
if input number 4 is already inside [[2,4],[7,8]], nothing will change.
if input number 13 is new to all ranges, it will insert it to the right, sorted position, like [[2,4],[7,8],[13]]
please help me with JavaScript native function (reduce prefer) or lodash.
Expected Behavior as below examples:
Example 1
originArray [[1,3],[7,10]]
input 5
output [[1,3],[5],[7,10]]
input 6
output [[1,3],[5,10]]
6 is will connect 5 and 7, so make it [5,10].
input 13
output [[1,3],[5,10],[13]]
Example 2
originArray []
input 3
output [[3]]
input 4
output [[3,4]]
input 2
output [[2,4]]
input 7
output [[2,4],[7]]
Here is a simple solution:
function combineValues(originArray) {
var i = 0;
while (i < originArray.length-1) {
if (originArray[i+1][0] - originArray[i][originArray[i].length-1] <= 1) {
// combine intervals
var newInterval = [originArray[i][0], originArray[i+1][originArray[i+1].length-1]];
originArray.splice(i, 2);
originArray.splice(i, 0, newInterval);
} else {
i++;
}
}
}
function updateRanges(originArray, element) {
for (var i = 0; i <= originArray.length; i++) {
// if smaller than current range, insert new singleton or extend
if (i === originArray.length || element < originArray[i][0]) {
originArray.splice(i, 0, [element]);
break;
}
}
combineValues(originArray);
}
// testing
var updates = [3, 8, 7, 2, 9, 10, 1, 5, 6, 13];
var arr = [];
for (var u = 0; u < updates.length; u++) {
updateRanges(arr, updates[u]);
console.log(arr);
}
If you are concerned with the time complexity of your program, you can look into binary searching.
This is easy to mis-explain so I'll simplify it. Let's say I have an array that are the results of dice throws. Like:
1 2 4 6 1 2 6 6 2 4 etc
Every time you throw a 6, you win. I want to create a new array which contains after how many turns you would win based on the original array. So the above array would create an array that is:
4 3 1
(it takes 4 turns to win, then 3, then 1)
So I only want to count the distance between the 6's. (I could also convert the dice results to binary win/lose)
How do I do this in excel? (or javascript, but really prefer excel)
Create a Helper Column (Column A of Excel). Put 1 in the first cell (A2) of Helper column. Follow it up with the formula (in A3) =IF(B3=6,A2+1,A2).Drag it to the last row of to the given array.
Then Create a Result column (Column C of Excel). Type in formula (in C2)
=IF(ROW()-1=MAX(A:A),"",IF(IF(ROW()-1=1,COUNTIF(A:A,ROW()-1)+1,COUNTIF(A:A,ROW()-1))=0,"",IF(ROW()-1=1,COUNTIF(A:A,ROW()-1)+1,COUNTIF(A:A,ROW()-1))))
in the first cell of Result Column (Column C of Excel). Drag and get the required result.
Hide Helper Column.
Note: Array Data starts from cell B2
If the first array is B1:K1 the second might be created with:
=IF(B1=6,COLUMN()-SUM(A2:$B2)-1,"")
in B2 and copied across to suit.
This might work for you:
var rollsUntil6 = function(rolls) {
return rolls.reduce(function(indices, roll, idx) {
if (roll == 6) {indices.push(idx);} return indices;
}, [-1]).map(function(val, idx, arr) {
return val - arr[idx - 1];
}).slice(1);
};
rollsUntil6([1, 2, 4, 6, 1, 2, 6, 6, 2, 4]); //=> [4, 3, 1]
What you need to do is iterate over the array and count the spaces by accumulating into a collector variable. You can find the code below it just pops into and alert window.(Javascript)
var array = [1, 2, 4, 6, 1, 2, 6, 6, 2, 4]
var resultArray = []
var i = 0;
var distance = 0;
for (i = 0; i < array.length; i++) {
distance++;
if (array[i] == 6) {
resultArray.push(distance);
distance = 0;
}
}
alert(resultArray);
I took an attempt at doing in excel.
You can place a command button and define a sub function like below and you will get the results expected. For instructions on how to place a command button http://www.excel-easy.com/vba/create-a-macro.html#command-button
Sub DistanceOf6InString(x As String)
Size = Len(x)
distance = 0
result = ""
Dim i As Integer
For i = 1 To Size
distance = distance + 1
If (Mid(x, i, 1) = "6") Then
result = result & distance
distance = 0
End If
Next i
MsgBox result
End Sub
Private Sub CommandButton1_Click()
DistanceOf6InString ("1246126624")
End Sub
You can repeatedly find the array.indexOf(6,lastmatch)
var array= [1, 2, 4, 6, 1, 2, 6, 6, 2, 4];
var resultArray= [], i, incr= 0;
while((i= array.indexOf(6, incr))!= -1){
i+= 1;
resultArray.push(i-incr);
incr= i;
}
resultArray returned value: (Array) [4,3,1]