How to rollback/replay some operations conditionally? - javascript

I want to get a stream which emits numbers and each number is distinct from the previous one or the all previous numbers.
The stream below outputs may be [0, 1, 1, 1, 2, 1, 0, ...], I expect some modifications to get [0, 2, 1, 2, 0, 1, ...], no two or more adjacent numbers are same in the sequence:
const number$ = Rx.Observable.interval(500)
.map(() => Math.floor(Math.random() * 3))
number$.subscribe(console.log)
The stream below outputs may be [3, 3, 1, 4, 3], I expect some modifications to get [2, 0, 3, 1, 4], all numbers are distinct:
const number$ = Rx.Observable.interval(500)
.map(() => Math.floor(Math.random() * 5))
.take(5)
number$.subscribe(console.log)
Simply using distinct and distinctUntilChanged will make some 'holes', it isn't desired. Pre-generate the determinated sequence(ex: using lodash.shuffle) is also not the desired solution, the output number is may generated by a remote rand generator service, means that we cloud retry number fetching while get duplicated numbers.
I think if there are some ways to get the comparison result of distinct and distinctUntilChanged and using it to conditionally rollback/replay the last (one or some) operation(s) can solve my problem.

Related

Function for calculating dice odds when rolling multiple die

I'm working on a way to display dice statistics like you can see at the site https://anydice.com/ , I've spent a bit looking through the source code but it's pretty thick alltogether so i decided to ask here. Basically, all i need help with is making a function that:
Lets you pick a dice with a certain amount sides, for example: 6.
Lets you pick how many times you want to roll this dice.
Returns the percentages of rolling each possible number with said dice.
I know the question might be a bit shitty, but this is kind of my last resort.
So far, I've tried finding the functions and stumbled upon this medium blog however I was wondering if it could maybe be done with percentages.
Here's a way.
// Two 6-sided dice, one 8-sided
const dice = [
[1, 2, 3, 4, 5, 6],
[1, 2, 3, 4, 5, 6],
[1, 2, 3, 4, 5, 6, 7, 8],
];
// Function to get all combinations of two arrays
function cartesianProduct(a, b) {
return a.flatMap(c => b.map(d => [c, d].flat()));
}
// Function to get sum of two numbers
function sum(a, b) { return a + b; }
// All combinations of all dice
const allPossibleRolls = dice.reduce(cartesianProduct);
// Sum for each set of rolls
const sums = allPossibleRolls.map(rolls => rolls.reduce(sum));
// Count how many times each sum appears
const counts = sums.reduce((acc, n) => Object.assign(acc, {
[n]: (acc[n] || 0) + 1
}), {});
// Convert each count into a percent by dividing by length of allPossibleRolls
const percents = Object.fromEntries(Object.entries(counts).map(
([sum, count]) => [sum, count / allPossibleRolls.length]));
Object.entries(percents).forEach(([k,v]) => {
console.log(`${k} = ${(v * 100).toFixed(5)}%`);
});
Doesn't dedupe equivalent rolls like the Medium post you linked to mentions, so the rolls [1, 2] and [2, 1] and treated as separate possibilites. Not sure if that throws off the math. But this returns the same answer as AnyDice.

sorting an array according to the order of another array - pair inputs [duplicate]

This question already has answers here:
sort 2 array with the values of one of them in javascript
(4 answers)
Closed 2 years ago.
so I have two arrays - arrOne = [10, 2, 3, 14, 1] and arrTwo = [1, 2, 3, 5, 4];
I want sort the arrTwo and use the same indexing changes on arrOne, ie arrTwo = [1, 2, 3, 4, 5], arrOne [10, 2, 3, 1, 14].
I've been trying to implement it with merge sort, but it does not work. The recursion obstructs me from doing what I intended.
Important to note, I am getting the data as two integers at a time and push them into separate arrays, using the previous arrays that would mean -
input 10 ,1
input 2, 2
input 3, 3
input 14, 5
input 1, 4
Perhaps a different data structure could be used, but I am not aware of it.
I have put go as a tag since I would like to solve it both languages.
Create a 2d array which holds value of 2 arrays and extract 2 arrays after sorting.
let arrOne = [10, 2, 3, 14, 1],
arrTwo = [1, 2, 3, 5, 4];
arrOne
// create 2d array which contains both array values
.map((v, i) => [v, arrTwo[i]])
// sort the combined array based on first array element
.sort(([a], [b]) => a - b)
// update the main arrays
.forEach(([v1, v2], i) => {
arrOne[i] = v1;
arrTwo[i] = v2;
})
console.log(arrOne, arrTwo)
To solve this I would not use two arrays.
I would push an object to a single array. Making it much more structured keeping the data “together”
const data = [{
one: 10,
two: 1
},
{
one: 2,
two: 2
},
{
one: 3,
two: 3
},
{
one: 14,
two: 5
},
{
one: 1,
two: 4
}
To add another input:
data.push({
one: 200,
two: 6
})
Then sort by key “two”
data.sort((a, b) => {
return a.two-b.two
})
Just note that the sort will mutate the array but you can copy if this is an issue. Guessing sorting the original array is not a problem for your use case anyway.

what to do? javascript array exercise

Find the correct passcode in the array and we'll do the rest. We can't disclose more information on this one, sorry.
Each entry in the first array represents a passcode
- Find the passcode that has no odd digits.
- For each passcode, show us the amount of even digits.
- If it has no odd digits, show us that you've found it and increase the number of terminals by one.
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3],
];
so, i've tried almost everything i could think of. modulo, function, for loop and i can't seem to get it. i'm a beginner and this is an important exercise i have to do. but what do i do? it asks for the amount of even digits in each passcode, so i have to get the array within the array and then code something that i don't know to find even values. i'm stuck
Your question is not really suitable for StackOverflow, you should at least try to write something and see how far you get.
Anyhow, you seem to want to iterate over the elements in passcodes to find the array with no odd numbers.
The first task is to how to determine if a number is even. That is as simple as looking for the remainder from modulus 2. If the remainder is zero, then the number is even, otherwise it's odd.
So a simple test is:
var isEven;
if (x % 2 == 0) {
isEven = true;
} else {
isEven = false;
}
Since 0 type converts to false, and the not (!) operator reverses the truthiness of values and converts the result to boolean, the above can be written:
var isEven = !(x % 2);
There are many ways to iterate over an array, if your task was just to find the element with no odd numbers, I'd use Array.prototype.every, which returns as soon as the test returns false, or Array.prototype.some, which returns as soon as the test returns true.
However, in this case you want to count the number of even numbers in each element and find the first with all even numbers. One way is to iterate over the array and write out the number of even numbers in the element, and also note if its all even numbers. You haven't said what the output is expected to be, so I've just made a guess.
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3], // this last comma affects the array length in some browsers, remove it
];
// Set flag for first element with all even numbers
var foundFirst = false;
// Iterate over each element in passcodes
passcodes.forEach(function(code) {
// Count of even numbers in current array
var evenCount = 0;
// Test each element of code array and increment count if even
code.forEach(function(num) {
if (!(num % 2)) ++evenCount;
});
// If all elements are even and haven't found first yet, write out elements
if (code.length == evenCount && !foundFirst) {
console.log('Passcode (first all even): ' + code.join());
// Set flag to remember have found first all even array
foundFirst = true;
}
// Write count of even numbers in this array
console.log('Even number count: ' + evenCount + ' of ' + code.length + ' numbers.');
});
I have no idea what you meant ...but it does all what i could understand from your question. Hope it will help :)
var passcodes = [
[1, 4, 4, 1],
[1, 2, 3, 1],
[2, 6, 0, 8],
[5, 5, 5, 5],
[4, 3, 4, 3],
];
var aPassCode;
while(aPassCode = passcodes.shift()){
for(var i=0,evenCount=0,totalCount=aPassCode.length;i<totalCount;i++){
if(aPassCode[i] % 2 == 0)evenCount++;
}
if(evenCount == totalCount){
console.log('all digits even here: ' + aPassCode.join(','));
}else{
console.log(aPassCode.join(',') + ' contains ' + evenCount + ' even digits.');
}
}

Find largest adjacent product in array (JavaScript)

I'm trying to understand the following solution for finding the largest adjacent product in any given array.
Example:
For inputArray = [3, 6, -2, -5, 7, 3], the output should be
adjacentElementsProduct(inputArray) = 21.
7 and 3 produce the largest product.
Possible solution in JS:
function adjacentElementsProduct(arr) {
return Math.max(...arr.slice(1).map((x,i)=>[x*arr[i]]))
}
I am having a hard time understanding two things:
What do the three dots exactly do and how does this get passed into the function? Is there any way to write this in a more understandable way? I know that is the "spread syntax" feature in ES6, but still don't understand completely.
Why do we insert "1" as argument to slice? My first though was to input "0", because we want to start at the start, then loop through everything, and see which adjacent product is the largest.
I'd appreciate any advice, links and explanations.
Thanks.
Cheers!
1. What do the three dots exactly do and how does this get passed into the function? Is there any way to write this in a more understandable way? I know that is some kind of "spread" feature in ES6, but still don't understand completely.
The Math#max needs a list of numbers as parameters, and map produces an array. The spread syntax is used to convert an array to be expanded to a list of parameters.
const arr = [1, 2, 3];
console.log('max on array', Math.max(arr));
console.log('max on list of parameters', Math.max(...arr));
In this case you can use Function#apply to convert the array to a list of parameters. I find it less readable, however.
const arr = [1, 2, 3];
console.log(Math.max.apply(Math, arr));
2. Why do we insert "1" as argument to slice? My first though was to input "0", because we want to start at the start, then loop through everything, and see which adjacent product is the largest.
Lets break down the iteration order of the 2 arrays.
[3, 6, -2, -5, 7, 3] // inputArray
[6, -2, -5, 7, 3] // inputArray.slice(1)
Now on each iteration of inputArray.slice(1):
x: 6, i = 0, arr[0] = 3
x: -2, i = 1, arr[1] = 6
x: -5, i = 2, arr[2] = -2
Since the inputArray.slice(1) array starts from the 2nd element of the inputArray, the index (i) points to the 1st element of the inputArray. And the result is an array of products of 2 adjacent numbers.
var biggestProduct = inputArray[0] * inputArray[1];
for (i=0; i<inputArray.length-1 ; ++i)
{
console.log(biggestProduct)
if ((inputArray[i] * inputArray[i+1] ) > biggestProduct)
{
biggestProduct = inputArray[i] * inputArray[i+1]
}
}
return biggestProduct;
Note: I've declared a variable that consists of 2 input arrays with index number then starts a for loop that indicates input array with his index number, so by that he will go throw all the index number of the array (one of them raised by one so that they won't be at the same value). and at the end of the code, you have the if statement.
You may simply do as follows;
function getNeigboringMaxProduct([x,...xs], r = -Infinity){
var p = x * xs[0];
return xs.length ? getNeigboringMaxProduct(xs, p > r ? p : r)
: r;
}
var arr = [3, 6, -2, -5, 7, 3],
res = getNeigboringMaxProduct(arr);
console.log(res);

Is it safe to modify an array while looping it?

Is it safe to modify an array while looping it, such as push an element?
I'm using underscore each method
I recommend avoid each unless you absolutely need to cause a side effect for every item in a collection (trigger an event, print out a result, etc.). For simply modifying your collection, there are better ways.
If each added element is only the result of an individual input element, the typical functional pattern would be to flatmap the array, which can be thought of a two steps:
Using map to apply a function that for each element generates an array as a result. The overall result will be an array of arrays.
Using flatten on that array of arrays to get a one dimensional array.
Using underscore or lodash:
var origArray = [1, 2, 3, 4];
var duplicateIf3 = function (val) { return val === 3 ? [val, val] : val; };
_.flatten(origArray.map(duplicateIf3));
// -> [1, 2, 3, 3, 4]
(In typed FP, the function would have to return [val] for values that aren't 3, but flatten doesn't care--it flattens whatever you give it to one dimension.)
If the new element is dependent on all that came before it, you would probably use a reduce or fold instead, with the empty array as the initial value.
var origArray = [1, 2, 3, 4];
origArray.reduce(function (acc, val) { return acc.concat(acc).concat(val); }, []);
// -> [1, 1, 2, 1, 1, 2, 3, 1, 1, 2, 1, 1, 2, 3, 4]
(Sorry I couldn't think of a realistic example, but here every step uses the full output of all previous steps in a pretty simple way for illustrative purposes, and you can see from each value of the original array what's going on. Also note that you can make your own flatten from reduce, if you don't want to use underscore/lodash)
reduce is more general than flatmap, but both methods are able to convert an array into a larger array that some how depends on the first one.
If you're interested in learning more about this, I highly recommend checking out the free (online) Javascript Allongé, by Reg Braithwaite.
I'm not sure what you mean by safe, but you'd have to have a good reason to do it. I played around with it a bit, and here's what I got:
_.each(a, function(el) {
if (el % 2 == 0)
a.push(el + 1);
console.log(el);
});
// logs 1, 2, 3, 4, 5
console.log(a);
// logs [ 1, 2, 3, 4, 5, 3, 5 ]
In this case, there is no negative affect unless you wanted to go through the added elements, but you could find yourself in trickier situations if you're changing the specific elements:
_.each(a, function(el, index) {
a[index + 1] = el - 1;
if (el % 2 == 0)
a.push(el + 1);
console.log(el);
});
// logs 1, 0, -1, -2, -3
It would make more sense to use _.map for most use cases.

Categories

Resources