Java Script. How to choose any few items of array - javascript

I'm designing a quiz motivator, i.e. if a user inputs any number of correct answers he's gonna get rewarded with a "star" or smth. The array in a pseudo code below represents a range of correct answers to choose from:
var rightAnswers = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
if (rightAnswers.chooseAny(3)) {user gets a star}
else if (rightAnswers.chooseAny(6)) {user gets 2 stars}
else if (rightAnswers.chooseAny(9) {user gets 3 stars}
I haven't found anything that would work instead of my pseudo "chooseAny()", any ideas, please?

You probably aren't looking for a chooseAny function; I think what you're really asking for is a way to count how many answers were correct given a set of answers and an answerKey.
The getTotalCorrect function below does that for you using a for-loop and identity comparison, and you can use getStars to determine how many stars should be awarded based on the score that is returned.
var answerKey = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
function getTotalCorrect (answers, answerKey) {
for (var correct = 0, i = 0; i < answerKey.length; i++) {
if (answers[i] === answerKey[i]) correct++
}
return correct
}
function getStars (totalCorrect) {
return (totalCorrect / 3) | 0
}
var totalCorrect = getTotalCorrect(['a', 'a', 'c', 'c', 'e', 'e', 'e'], answerKey)
console.log(totalCorrect) //=> 3
var stars = getStars(totalCorrect)
console.log(stars) //=> 1

Related

How to return index and value of the specific element from array on callback using any JavaScript array function?

I tried with filter() function but I'm not sure about returning index and value using that. here's sample code that I tried.
var names = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
const name = names.filter((name, index) => name === 'G' ? console.log(${index}: ${name}) : null)
here variable name is useless because on call back I'm returning nothing.
However, I can access index and name inside callback but not sure about returning both.
Use findIndex instead
var names = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
var valToFind = "G";
const valIndex = names.findIndex( s => s === valToFind );
you already know that the value is valToFind, so no need to return it.
Or as #PaulPro pointed out, if the values are just strings, then simply use
const valIndex = names.indexOf( valToFind );
Or you can wrap it in an object
var output = { name : valToFind, index : names.indexOf( valToFind ) };

JS bracket notation clarification

Thanks in advance. I have a concept question in JavaScript;
function rand(x,z)
{ return x + Math.floor((z-x+1)*Math.random()); }
function getLetter()
{ return ['a', 'b', 'c', 'd', 'e', 'f'][rand(0,5)]; }
console.log(getLetter()); // f // a // c .....
I'm having trouble understanding how the getLetter() function logs a randomly selected letter just by returning two arrays. If I reverse the the array order it is logged in console as undefined.
Ultimately, I haven't seen this syntax before and it threw me off guard. Does the getLetter() function behave the same way as a .map() and .filter() approach?
See the returned value as a row randomly picked up from an array:
var letters = ['a', 'b', 'c', 'd', 'e', 'f']
like
Array (
0 => 'a',
1 => 'b',
2 => 'c',
3 => 'd',
4 => 'e',
5 => 'f'
)
The [rand(0,5)] is the row selector (random number from the first row id to the last row id, which are from 0 to 5).
Your getLetter() function can be seen as:
function getLetter() {
var letters = ['a', 'b', 'c', 'd', 'e', 'f'];
return letters[rand(0,5)];
}
rand returns a random integer between the two numbers passed in (inclusively-- 0 and 5 are valid returns, as are any integer in between).
getLetter leverages it as a means to get a random index in an array of letter that contains six letters. So this:
['a', 'b', 'c', 'd', 'e', 'f'][rand(0,5)]
Calls rand. And let's pretend it returns 2. So then we have:
['a', 'b', 'c', 'd', 'e', 'f'][2]
Which is the third item in the array, so 'c' is returned.
There are no two arrays. There is one array and using bracket notation to reference an index in the array. Below is what the code basically does:
function getLetter() {
var options = ['a', 'b', 'c', 'd', 'e', 'f'], //defined array
randomNumber = rand(0,5), //generate random number
selection = options[randomNumber]; //reference index with the random number
return selection; //return the value
}
Your getLetter function is actually returning an element of a single dimension array. Basically it is creating an array of 6 characters (a thru f) and then returns the one pointed to by the index generated by the rand function.
The reverse (return [rand(0,5)]['a', 'b', 'c', 'd', 'e', 'f'];) doesn't work because the array object generated in that case is a one element array (which contains a random number between 0 and 5).
The rand function is just returning a number in the inclusive interval [0, 5].
getLetter will just return the charcater in the ['a', 'b', 'c', 'd', 'e', 'f'] at the random character genered by rand.
['a', 'b', 'c', 'd', 'e', 'f'] is an array, expression[x] is on the other hand getting the element at the x index in the expression array starting from zero.

Lodash method to check whether all elements in an array are in another array

I have 2 arrays of string. I want to make sure all elements of the second array are in the first. I use Lodash/Underscore for things like this. Its easy when checking if one astring is in an array:
var arr1 = ['a', 'b', 'c', 'd'];
_.includes(arr1, 'b');
// => true
But when its an array, I cant see a current method to do it. What I've done is:
var arr1 = ['a', 'b', 'c', 'd'];
var arr2 = ['a', 'b', 'x'];
var intersection = _.intersection(arr1, arr2);
console.log('intersection is ', intersection);
if (intersection.length < arr2.length) {
console.log('no');
} else {
console.log('yes');
}
Fiddle is here. But its rather long-winded. Is there a built in Lodash method?
You could use _.xor for a symmetric difference and take the length as check. If length === 0, the both arrays contains the same elements.
var arr1 = ['a', 'b', 'c', 'd'],
arr2 = ['a', 'b', 'x'];
console.log(_.xor(arr2, arr1));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

How to get the even and odd entries from an array with Ramda

I have the following:
var isEven = function (n) { return n % 2 === 0; }
var isOdd = function (n) { return n % 2 !== 0; }
var indexedList = function(fn, list) {
var array = [];
for (var i = 0; i < list.length; i++) {
if (fn(i)) {
array.push(list[i]);
}
}
return array;
}
Is there a Ramda equivalent of IndexedList so I can have an array of just the even index based elements and an array of odd based index elements.
Ramda's list-based functions by default do not deal with indices. This, in part, is because many of them are more generic and also work with other data structures where indices don't make sense. But there is a standard mechanism for altering functions so that they do pass the indices of your lists along: addIndex.
So my first thought on this is to first of all, take your isEven and extend it to
var indexEven = (val, idx) => isEven(idx);
Then you can use addIndex with filter and reject like this:
R.addIndex(R.filter)(indexEven, ['a', 'b', 'c', 'd', 'e']);
//=> ['a', 'c', 'e']
R.addIndex(R.reject)(indexEven, ['a', 'b', 'c', 'd', 'e']);
//=> ['b', 'd']
Or if you want them both at once, you can use it with partition like this:
R.addIndex(R.partition)(indexEven, ['a', 'b', 'c', 'd', 'e']);
//=> [["a", "c", "e"], ["b", "d"]]
You can see this in action, if you like, on the Ramda REPL.
If the list length is even, I would go with
R.pluck(0, R.splitEvery(2, ['a','b','c']))
The disadvantage of this is that it will give undefined as a last element, when list length is odd and we want to select with offset 1 ( R.pluck(1) ). The advantage is that you can easily select every nth with any offset while offset < n.
If you can't live with this undefined than there is another solution that I find more satisfying than accepted answer, as it doesn't require defining a custom function. It won't partition it nicely though, as the accepted answer does.
For even:
R.chain(R.head, R.splitEvery(2, ['a','b','c','d']))
For odd:
R.chain(R.last, R.splitEvery(2, ['a','b','c','d']))
As of Ramda 0.25.0, the accepted solution will not work. Use this:
const splitEvenOdd = R.compose(R.values, R.addIndex(R.groupBy)((val,idx) => idx % 2))
splitEvenOdd(['a','b','c','d','e'])
// => [ [ 'a', 'c', 'e' ], [ 'b', 'd' ] ]

How to split an array in half until chunks of a certain size are reached?

I have an array with a variable length that is greater than 3 and can be odd or even.
For example: var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
Now I want to split that array into halves.
['a', 'b', 'c', 'd', 'e'] and ['f', 'g', 'h', 'i', 'j']
Next I want to split those chunks into halves and to keep doing that until the chunks have a length of 3 or 2.
Finally I want to store those chunks in a new array.
var newarr = [['a','b','c'],['d','e'],['f','g','h'],['i','j']];
How would I do this?
A self-suggesting way to do this is to use a recursive function F: for an input array arr if its length is <= 3 then the result is [arr], otherwise it is F(first_half_of_arr) concatenated with F(second_half_of_arr).
In code this translates to:
function recursiveSplit(arr) {
return arr.length <= 3 ? [arr] :
recursiveSplit(arr.slice(0, Math.ceil(arr.length / 2)))
.concat(recursiveSplit(arr.slice(Math.ceil(arr.length / 2))));
}
You can exclude the Math.ceil calls, but if you do you are going to get the 2-length chunks before the 3-length ones in your result.
Now in practice an iterative implementation should be much more performant than a recursive one because it won't need to create and abandon small arrays entirely, so if this is expected to operate on large arrays you should probably stay away from recursion.
var arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
var arr1 = arr.splice(0, Math.ceil(arr.length / 2));
That will split an array in half, so now arr contain second half of original array and arr1 contains first half.
You should be able to just repeat in a while loop:
while (arr > 3) {
//continue splicing
}
If you don't think this answer is good enough (It probably makes no sense to anyone other than me, I am so tired right now) please just comment rather than disliking.

Categories

Resources