Javascript - how to pick random elements from an array in order? - javascript

I have an array
var numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];
and trying to get random items from it, so:
console.log(_.sample(numbers, 5));
this will give me 5 random numbers (strings) from the array in a random order, like:
"17", "2", "3", "18", "10"
How do I get a sorted list or random items, like?
"2", "3", "10", "17", "18"
_.sample will probably not be the best choice here. I am trying to get random items from a given array and have these items picked up from left to right of the array.
How to do this in javascritp?
Thank you.
EDIT: I have an array of strings, not numbers, so I cannot sort the randomly picked items.
EDIT2: To avoid confusing, in the array are words (= strings), I used there numbers as strings to more easily demonstrate what I am trying to achieve. (sorry for possible confusions)

You can use Array.prototype.sort to sort the returned array:
ie.
_.sample(numbers, 5).sort(function(a, b) { return parseInt(a, 10) - parseInt(b, 10) })
A better random would be:
var randomChoice = numbers[~~(Math.random() * numbers.length)]
Note: the ~~ performs the same action as Math.floor() in this context. They can be interchanged.
All together:
var numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];
var randomSample = []
for(var i=0; i < 5; i++) {
var randomChoice = numbers[~~(Math.random() * numbers.length)]
randomSample.push(randomChoice)
}
var sortedRandomSample = randomSample.sort(function(a, b) { return parseInt(a, 10) - parseInt(b, 10) })
Demo: https://jsbin.com/zosizefaga/edit?html,js,console,output

Here is a solution that doesn't make any assumption about the original order. The idea is to lookup the element's position in the original array and sort by that. However, that assumes that every element is unique.
sample.sort(function(a, b) {
return numbers.indexOf(a) - numbers.indexOf(b);
});
This will also be quite slow for large arrays.

Why don't you implement your own method of sample and after calling _.sample you call the method sort?

The easiest method I can think of is as follows:
var randomSample = _.sample(numbers.map(function(v,i){ return i; }), 5)
.sort(function(a,b){ return a-b; })
.map(function(v){ return numbers[v]; });
That is, make a temporary array that holds the indices of the original array, i.e., just the numbers 0 through numbers.length - 1):
var indices = numbers.map(function(v,i){ return i; })
Take a random sample from that array:
var sampleIndices = _.sample(indices, 5)
Sort the sample:
sampleIndices.sort(function(a,b){ return a-b; })
Then use the sorted, randomly selected indices to get values out of the original array:
var randomSample = sampleIndices.map(function(v){ return numbers[v]; });
And as shown at the beginning of my answer, you can do it all in one line without using the indices and sampleIndices variables. Although if you are going to be regularly taking samples from the same numbers array it would probably make sense to keep the indices variable to save rebuilding it every time, especially if the original array is quite large.
This will work regardless of what type of values are in the original array, because those values are just selected out at the end once random indices have been selected.

Try this:
function random(array, elements) {
return array.concat().sort(function() {
if (Math.random() < 0.5) {
return -1;
} else {
return 1;
}
}).slice(0, elements).sort(
function(a, b) {
return a - b
});
}
Here's the fiddle:
JSFiddle

This is a proposal without sorting and uses an helper array random for the selected items.
First get an empty array, then fill with true until count elements are filled and the filter the original array with the random selected positions.
This solution works for any content of the given array, without sort or lookup with indexOf.
function getSortedRandom(array, count) {
var random = array.map(function () { return false; }),
r;
while (count) {
r = Math.floor(Math.random() * array.length);
if (!random[r]) {
random[r] = true;
count--;
}
}
return array.filter(function (_, i) {
return random[i];
});
}
var random = getSortedRandom(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"], 5);
document.write('<pre>' + JSON.stringify(random, 0, 4) + '</pre>');

As of lodash 4.0.0, you can use the _.sampleSize function in conjunction with sort:
var numbers = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"];
var randomSample = _.sampleSize(numbers, 5).sort();
console.log(randomSample);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.14.1/lodash.min.js"></script>

Related

Array's elements in JavaScript [duplicate]

This question already has answers here:
Get the element with the highest occurrence in an array
(42 answers)
Counting the occurrences / frequency of array elements
(39 answers)
Closed 28 days ago.
What am I trying to do:
Given an array of numbers, for example: ["1", "2", "1", "1", "2", "2", "3"],
I want to find the element that is most repeated in the array.
But, I also want to know if there is more than 1 element that satisfies the requirement, and what are those elements.
I couldn't think of any idea on how to start with this yet...
This is an approach using Array.reduce()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
First I determine for each unique value in the array how many times it does occur, by returning an object like {"1": 3, "2": 3, "3": 1}
Then I determine which are the values occurred most of the times
in the array, by returning an object like {"count": 3, "values": ["1", "2"]}
const data = ["1", "2", "1", "1", "2", "2", "3"];
//returns the number of time each unique value occurs in the array
const counts = data.reduce( (counts, item) => {
if(item in counts)
counts[item] += 1;
else
counts[item] = 1;
return counts;
}, {});
console.log(counts);
/*
{
"1": 3,
"2": 3,
"3": 1
}
*/
//returns which values and how many times occur the most
const max = Object.entries(counts)
.reduce((max, [value, count])=> {
if(count < max.count)
return max;
if(count == max.count){
max.values.push(value);
return max;
}
return {count: count, values: [value]};
},{count: 0, values: []});
console.log(max);
/*
{
"count": 3,
"values": [
"1",
"2"
]
}
*/

Filter object properties based on array of keywords

Looking for a way to get only the objects in the 'test' object that contain either one of the 'asSrcElementsTypes' values
What is the best way to map over the array to check if they are any of those values? I keep getting errors with the below code when I try to map the array to see if it matches the key in the test object.
var asSrcElementsTypes = ['-input', '-src'];
var test = { "exitUrl":"googl.com", "otherData1":"otherData1" "F2-1_largerLegal-input": "F2-1_largerLegal-input", "F2-1_copy-font": "Ultra", "F2-3_copy-fontSize": "12", "F2-1_copy-input": "F2-1_copy-input", "F2-1_frameLegal-input": "Ultra", "F2-1_frameLegal-fontSize": "14", "F2-2_copy-input": "F2-2_copy-input", "F2-3_copy-input": "F2-3_copy-input", "F2-3_copy-font": "Medium", "F2-1_copy-fontSize": "10", "F2-1_product-src": "250/50/F2-1_product.png", "F2-2_copy-font": "Medium", "F2-2_copy-fontSize": "11", "F2-1_largerLegal-fontSize": "13"};
const allButMe = data.filter(function(value, key){ if(key.indexOf.indexOf(asSrcElementsTypes.map()) !== -1){return key}});
Do you mean something, like that?
const asSrcElementsTypes = ['-input', '-src'],
test = { "F2-1_largerLegal-input": "F2-1_largerLegal-input", "F2-1_copy-font": "Ultra", "F2-3_copy-fontSize": "12", "F2-1_copy-input": "F2-1_copy-input", "F2-1_frameLegal-input": "Ultra", "F2-1_frameLegal-fontSize": "14", "F2-2_copy-input": "F2-2_copy-input", "F2-3_copy-input": "F2-3_copy-input", "F2-3_copy-font": "Medium", "F2-1_copy-fontSize": "10", "F2-1_product-src": "250/50/F2-1_product.png", "F2-2_copy-font": "Medium", "F2-2_copy-fontSize": "11", "F2-1_largerLegal-fontSize": "13"},
result = Object.fromEntries(
Object
.entries(test)
.filter(([key,value]) =>
asSrcElementsTypes
.some(type =>
key.includes(type)))
)
console.log(result)
.as-console-wrapper{min-height:100%;}
Or, maybe, alternative .reduce()-based way:
const asSrcElementsTypes = ['-input', '-src'],
test = { "F2-1_largerLegal-input": "F2-1_largerLegal-input", "F2-1_copy-font": "Ultra", "F2-3_copy-fontSize": "12", "F2-1_copy-input": "F2-1_copy-input", "F2-1_frameLegal-input": "Ultra", "F2-1_frameLegal-fontSize": "14", "F2-2_copy-input": "F2-2_copy-input", "F2-3_copy-input": "F2-3_copy-input", "F2-3_copy-font": "Medium", "F2-1_copy-fontSize": "10", "F2-1_product-src": "250/50/F2-1_product.png", "F2-2_copy-font": "Medium", "F2-2_copy-fontSize": "11", "F2-1_largerLegal-fontSize": "13"},
result = Object
.keys(test)
.reduce((r,key) => (
asSrcElementsTypes.some(type =>
key.includes(type)) &&
(r[key]=test[key]), r), {})
console.log(result)
.as-console-wrapper{min-height:100%;}

Binary Search array of number strings not finding values

I know there are a ton of binary search examples, but I'm having difficulty getting any to work when I have a sorted array of numbered strings, for example.
const sortedStringNumbers = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"];
When I plug it into a binary search function like this:
function bsearch (Arr,value){
var low = 0 , high = Arr.length -1 ,mid ;
while (low <= high){
mid = Math.floor((low+high)/2);
if(Arr[mid]==value) return true;
else if (Arr[mid]<value) low = mid+1;
else high = mid-1;
}
return -1 ;
}
When I run:
bsearch(sortedStringNumbers, '3')
it returns -1
When I run :
bsearch(sortedStringNumbers, '26)
it returns true;
Lastly, the reason I simply don't convert the binary search input array is I need to use this function for two kinds of sorted arrays, the aforementioned kind, and others that contain words, such as: const sortedWordsArray = ['Algebra', 'Biology', 'Chemistry', ...]
The binary search array does work for word arrays, btw.
Check to make sure your array is sorted.
When you're making your comparison
Arr[mid]<value
or
Arr[mid]==value
They are being compared as strings rather than as numeric values.
If you'd like it to work in "both" scenarios, as you suggested, you could try something like this
function bsearch (Arr,value){
var low = 0 , high = Arr.length -1 ,mid ;
while (low <= high){
mid = Math.floor((low+high)/2);
var int_val = Arr[mid];
if (!isNaN(Arr[mid])) {
int_val = parseInt(Arr[mid]);
}
if(int_val==value) {
return true;
}
else if (int_val<value) {
low = mid+1;
}
else {
high = mid-1;
}
}
return -1 ;
}

Why am I getting a return of index two?

I can not understand why my return is index 2 and not index 0 in the for of loop.
function cardPicker() {
let cards = [
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"10",
"J",
"Q",
"K",
"A"
];
for (p of cards) {
return cards[p];
}
}
The for ... of loop iterates through the values of the array, not the indexes. Your loop therefore returns the value at index 2 in the array, the string "4". If you changed it to a for ... in loop, you'd get the string "2". Of course, there's no point to the loop at all because the only thing the loop does is return, so it will exit on the first iteration.
Also p should be declared with let or var.
p in your example will be "2", so you will return the index 2 of your array, which will returns "4".
Change this:
for (p of cards) {
return cards[p];
}
To this:
for (p in cards) {
return cards[p];
}

How to convert an array to Collection in backbone

I have an array defined as:
this.noOfHouseHold = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20"];
I'm trying to convert it to a Backbone Collection as:
var adultListCollection = new Backbone.Collection(this.noOfHouseHold);
It gives me the list but for 2 digit numbers, it shows something like this:
attributes: Object
0: "1"
1: "1"
I'm not able to understand as to what is wrong here or is it the wrong way I'm converting my array to collections. Please suggest. Thanks in advance!
A Backbone collection expects a list of models/hashes of attributes that can be converted to a model but you have a plain array.
You will have to transform your array to a list of hashes. Assuming your values are the ids of your models :
var lst = _.map(this.noOfHouseHold, function(val) {
return {id: val};
});
var adultListCollection = new Backbone.Collection(lst);
Backbone.Collection expects a list of models or objects (because they can be converted to Backbone.Model). In order to persist the array you have to convert those primitives into objects. Use Backbone.Collection.parse and _.map to turn your array of primitives into an array of objects:
var AdultListCollection = Backbone.Collection.extend({
parse: function (noOfHouseHold) {
var res = _.map(noOfHouseHold, function (n) {
return {id: n};
});
return res;
}
});
Now you can instantiate your Collection with an array:
var adultListCollection = new AdultListCollection(this.noOfHouseHold, {parse: true});
Example: JSFiddle

Categories