Given an array and an (variable) integer n, I want to create a new array comprising n number of consecutive elements of the array. I have it if n = 2 but I can't figure how to enable variable n:
var arr = ["first", "second", "third", "fourth", "fifth", "sixth" ];
var int = 3;
function consecEls(array, int) {
newArr = arr.map(function(val, ix, arr) {
var next = ix+1; // this works if I only needed firstsecond, secondthird, etc. but I need arbitrary # of consecutive els
// var next = ... ? ... next n els
var els = arr.slice(arr[ix], int); // or slice(ix, int) ... both return ["first", "second", "third"]
if (next !== arr.length) {
return val + arr[next];
}
else { return val; }
}) // forEach
return newArr;
}
consecEls(arr, int);
Any insight is much appreciated,
================================================
As I mentioned in the comments below, here's my very slightly modified version of #gyre's solution:
var arr = ["first", "second", "third", "fourth", "fifth", "sixth" ];
function map(array, groupSize, callback, context) {
var i = 0;
var result = [];
while (i < array.length) {
result.push(
callback.call(context, array.slice(i, i + groupSize), i, array)
)
i ++
}
return result
}
map(arr, 2, function (e) {
return e.join("")
})
================================================
ok, one more quick edit: I tweaked slightly further, to eliminate the callback:
function map(array, groupSize) {
var i = 0;
var result = [];
while (i < array.length) {
result.push(array.slice(i, i + groupSize).join(""))
i ++
}
return result
}
map(array, n);
Edit: #torazaburo's idea is actually a nicer separation of concerns than the function I had originally. I didn't realize that there was a name for that process of splitting up an array into fixed-length groups. However, here is my alternate implementation of a partition function because I think it could be a little cleaner, and include an optional offset parameter to allow skipping over the first few elements:
function partition (array, size, offset) {
offset |= 0
var result = []
while (offset < array.length) {
result.push(array.slice(offset, offset += size))
}
return result
}
var arr = ["first", "second", "third", "fourth", "fifth", "sixth" ],
example
// Groups of three, joined by spaces
example = partition(arr, 3).map(function (e) {
return e.join(' ')
})
console.log(example) //=> ["first second third", "fourth fifth sixth" ]
// A list of pairs
example = partition(arr, 2)
console.log(example) //=> [ ["first", "second"], ["third", "fourth"], ["fifth", "sixth"] ]
// A list of one-element arrays, skipping the first element
example = partition(arr, 1, 1)
console.log(example) //=> [ ["second"], ["third"], ["fourth"], ["fifth"], ["sixth"] ]
Original: Alright, it seems that I may have misunderstood your question the first time around. It looks like your goal is to map over groups of array elements; say, pairs instead of one at a time.
Below is a function map, which takes similar arguments to the native Array#map. Don't let the function signature intimidate you too much; it's pretty easy to use and you will rarely need to pass more than three parameters.
function map(array, groupSize, callback, offset, context) {
Parameters:
array — The array that you want to map over.
groupSize — The number of elements that you want to see at a time.
callback — The mapping function that you pass, which receives 1) a group of elements, 2) the index of the first element in the current group, and 3) the original array.
offset — The index at which the first group should begin; allows skipping of elements.
context — Determines what this is bound to in your callback.
Returns:
An array containing the return values, in order, of the calls made to callback for each group of elements.
Demo:
var arr = ["first", "second", "third", "fourth", "fifth", "sixth" ],
example
// Groups of three, joined by spaces
example = map(arr, 3, function (e) {
return e.join(' ')
})
console.log(example) //=> ["first second third", "fourth fifth sixth" ]
// A list of pairs
example = map(arr, 2, function (e) {
return e
})
console.log(example) //=> [ ["first", "second"], ["third", "fourth"], ["fifth", "sixth"] ]
function map(array, groupSize, callback, offset, context) {
var i = offset | 0,
result = []
while (i < array.length) {
result.push(
callback.call(context, array.slice(i, i + groupSize), i, array)
)
i += groupSize
}
return result
}
I think what you are looking for in the notion of "chunking" or "partitioning". This refers to splitting an array into sub-arrays according to some criteria, often length. There are many partitioning solutions out there; here we use a real simple one. However, note that this will destroy the original array.
Once you have partitioned your input, in your case you want to concatenate the elements of each subarray, so
function partition(array, n) {
return array.length ? [array.splice(0, n)].concat(partition(array, n)) : [];
}
var arr = ["first", "second", "third", "fourth", "fifth", "sixth" ];
var int = 3;
const result = partition(arr, int).map(subarray => subarray.join(''))
console.log(result);
Here is a more straight-forward partition implementation:
function partition(array, n) {
let result = [], cnt = 0, sub;
for (let i = 0; i < array.length; i++) {
if (!cnt--) cnt = n, result.push(sub = []);
sub.push(array[i]);
}
return result;
}
array.slice() if you want to leave the original array as it is
or
array.splice() if you want to remove the items from original array
for both functions you pass in the starting index and number of elements from that starting index on to "select/cut" from the original array
Related
I'm looking for a way to find the last index of an object in Javascript from a point in an array. For example:
array.lastIndexOf(object.key, start);
So far, I haven't found a good solution for this problem. I could splice the array from the 'start' point, reverse it, and then search the sliced array for the key value, but this seems like an inefficient solution to me.
EDIT:
To illustrate the problem a little more, I'm posting the code that I used in the end to solve the problem. Essentially; what I did was I used While to loop through the previous values in the array.
getLastValue = (index) => {
const arr = [
{'d':'01-02-2017','v':'123'},
{'d':'02-02-2017'},
{'d':'04-02-2017'},
{'d':'05-02-2017','v':'456'},
...
];
let lastValue;
while (arr[index] && !arr[index].v) {
index--;
}
lastValue = arr[index];
return lastValue;
}
Personally, I wouldn't choose either solution. Here is why:
LastIndexOf:
The problem lies in the comparing of elements while searching through the array. It does compare the elements using strict equality. Therefore comparing objects will always fail, except they are the same. In OP case they are different.
Slice & reverse one-liner #adeneo
Given an array of three elements [{key: A},{key: B},{key: C}] and the lookup for the last index of key = D will give you an index of 3. This is wrong as the last index should be -1 (Not found)
Looping through the array
While this is not necessarily wrong, looping through the whole array to find the element isn't the most concise way to do it. It's efficient yes, but readability can suffer from it. If I had to choose one, I'd probably choose this one. If readability / simplicity is your friend, then below is yet one more solution.
A simple solution
We can make lastIndexOf work, we just need to make the value comparable (strict equality conform). Or simply put: we need to map the objects to a single property that we want to find the last index of using javascript's native implementation.
const arr = [ { key: "a" }, { key: "b" }, { key: "c" }, { key: "e" }, { key: "e" }, { key: "f" } ];
arr.map(el => el.key).lastIndexOf("e"); //4
arr.map(el => el.key).lastIndexOf("d"); //-1
// Better:
const arrKeys = arr.map(el => el.key);
arrKeys.lastIndexOf("c"); //2
arrKeys.lastIndexOf("b"); //1
A fast solution
Simple backwards lookup (as concise and as fast as possible). Note the -1 return instead of null/undefined.
const arr = [ { key: "a" }, { key: "b" }, { key: "c" }, { key: "e" }, { key: "e" }, { key: "f" } ];
const lastIndexOf = (array, key) => {
for(let i = array.length - 1; i >= 0; i--){
if(array[i].key === key)
return i;
}
return -1;
};
lastIndexOf(arr, "e"); //4
lastIndexOf(arr, "x"); //-1
With ES2015 and findIndex you can pass a callback to look for an objects key.
If you make a copy of the array, and reverse it, you can find the last one by subtracting that index from the total length (and 1, as arrays are zero based)
It's not very efficient, but it's one line, and works well for normally sized arrays i.e. not a million indices
var idx = arr.length - 1 - arr.slice().reverse().findIndex( (o) => o.key == 'key' );
var arr = [{key : 'not'}, {key : 'not'}, {key : 'key'}, {key : 'not'}];
var idx = arr.length - 1 - arr.slice().reverse().findIndex( (o) => o.key == 'key' ); // 2
console.log(idx)
A more efficient approach would be to iterate backwards until you find the object you're looking for, and break the loop
var arr = [{key: 'not'}, {key: 'not'}, {key: 'key'}, {key: 'not'}];
var idx = (function(key, i) {
for (i; i--;) {
if (Object.values(arr[i]).indexOf(key) !== -1) {
return i;
break;
}
} return -1;
})('key', arr.length);
console.log(idx)
I think you want something like below:
var arr = [ { key: "a" }, { key: "b" }, { key: "c" }, { key: "e" }, { key: "e" }, { key: "f" } ];
console.log(lastIndexOf("e", 2));
function lastIndexOf(keyValue, start) {
for (var i = arr.length - 1; i >= start; i--) {
if (arr[i].key === keyValue) {
return i;
}
}
return null;
}
You can do this:
reverse your array: let newArr = arr.reverse()
use findIndex: newArr.findIndex(obj => obj.d == "your String")
i used sample code, like this:
//find last index in object array
const lastIndexOf = arr.reduce((acc,cur,idx)=>cur.key==xxx?idx:acc,-1)
//find last index of object in object array
const lastIndexOfObject = arr.reduce((acc,cur,idx)=>cur.key==xxx?cur:acc,undefined)
Just try to find last index in the whole massive and compare it to start
let ind = array.lastIndexOf(object.key);
if (ind > start) {return}
let a = [
{prop1:"abc",prop2:"incomplete"},
{prop1:"bnmb",prop2:"completed"},
{prop1:"bnmb",prop2:"prajapati"},
{prop1:"zxvz",prop2:"testAJ"},
{prop1:"last",prop2:"completed"},
{prop1:"last",prop2:"incomplete"},
{prop1:"last",prop2:"incomplete11"},
{prop1:"last",prop2:"incomplete"},
{prop1:"last",prop2:"incomplete"},
{prop1:"last",prop2:"incompleteness"},
];
let findLastduplicateObjectIndex = a.map(el => el.prop2).lastIndexOf("incomplete");
I am struggling to create a simple function that will taking an array such as
["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"]
and turn it into a multidimensional array that looks like this
[["chicken","10 lbs"],["hot sauce","4 cups"],["celery","1 stalk"]]
essentially index 0 and 1 merge into a new sub array then 2 and 3 merge and so on...
i am trying for loops where i increases +2 but i can't get it quite right, i thought this would be a simple solution but the loops i've made so far are almost crashing my browser...any help would be appreciated. thanks
EDIT: WOW Thanks for all the rapid responses! I looked at everything and learned a lot!
Using Array#reduce(), Array#concat() & Array#slice()
var data = ["chicken", "10 lbs", "hot sauce", "4 cups", "celery", "1 stalk"];
var res = data.reduce((a, c, i) => {
return i % 2 === 0 ? a.concat([data.slice(i, i + 2)]) : a;
}, []);
console.log(res)
Hope this helps...
I added some comments but feel free to ask if you need more explanation.
There are definitely more advanced (and much shorter!) ways of doing this, but this is the most intuitive and easiest to understand, in my opinion.
Right now, if there is an odd amount of elements, the last element will end up being "undefined." Let me know if you'd like this to work differently.
var array = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
function combineTwo(inputArray) {
//Starting with the beginning of the array, this function combines index 0 with 1, 2 with 3, and so on for the entire length of the array
var result = []; //this will the variable that we store our result in
for (var i = 0; i < inputArray.length; i+=2) {
//This for loop iterates through every other index of the array... for example: 0, 2, 4, etc.
result.push([inputArray[i], inputArray[i+1]]); //Adds i and i+1 as a new array to the result array
}
return result;
}
console.log(combineTwo(array));
There are many ways to do this. Here, we are using the Array.map() method to return items into a new array and then cleaning out any undefined elements using Array.filter().
var startArray = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
// Create a new array by iterating the first one...
var resultArray = startArray.map(function(item, index, arry){
// If we are on an even index...
if(index % 2 === 0){
// Send the item and the one that follows it into the new array
return [item, arry[index + 1]];
}
});
// The resulting array will contain undefined for each enumeration that didn't
// return anything, so we can clean that up by filtering out the undefined elements
resultArray = resultArray.filter(function( element ) {
return element !== undefined;
});
console.log(resultArray);
However, it seems that you want to make an array of ingredients and ingredients combine to make a final product, so creating an object would be more appropriate, since objects are really nothing more than groupings of key/value pairs and can be more versatile if you plan on doing OOP operations. The result here is an array of recipe objects:
// Create a new array that will store recipe objects
var cookbook = [];
function addRecipeToCookbook(ary){
// Create a "recipe" object
var recipe = {};
// Iterate the passed array...
ary.forEach(function(item, index, array){
// If we are on an even index...
if(index % 2 === 0){
// Add the item as a new property of the recipe object with the quantity as the value
recipe[item] = array[index + 1];
}
});
// Add the object to the new array
cookbook.push(recipe);
}
// Now you can add as many recipies as you like:
var recipeArray1 = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
var recipeArray2 = ["pork","2 lbs","BBQ sauce","2 cups","onion","3 ounces"];
var recipeArray3 = ["beef","5 lbs","worchestishire sauce","4 ounces","garlic","1 clove"];
// Just call the reusable function and pass a recipe array:
addRecipeToCookbook(recipeArray1);
addRecipeToCookbook(recipeArray2);
addRecipeToCookbook(recipeArray3);
console.log(cookbook);
Another option is to take in a second argument that dictates how many items you would like in each subarray. For instance:
function squash(arr, num) {
let results = [];
let start, end;
for (let i = 1; i < arr.length; i++) {
start = (i - 1) * num;
end = i * num;
let sliced = arr.slice(start, end);
if (start >= arr.length) { // need to make sure we don't go passed the end
break;
}
results.push(sliced);
}
return results;
}
Just another way to do this using .reduce():
var array = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
var array2d = array.reduce((array, element, index) => {
if (index % 2 > 0) {
array.push(array.pop().concat([element]));
} else {
array.push([element]);
}
return array;
}, []);
console.log(array2d);
A more generic method that could be used might look like the following:
function group(amount) {
return (array) => array
.reduce((array, element, index) => {
if (index % amount > 0) {
array.push(array.pop().concat([element]));
} else {
array.push([element]);
}
return array;
}, []);
}
var a = ["chicken","10 lbs","hot sauce","4 cups","celery","1 stalk"];
var b = ["chicken","10","lbs","hot sauce","4","cups","celery","1","stalk"];
var group2 = group(2);
var group3 = group(3);
var a2d = group2(a);
var b2d = group3(b);
console.log(a2d);
console.log(b2d);
most intuitive for me, just keep yanking items off the original array until it is empty:
let array = ["chicken", "10 lbs", "hot sauce", "4 cups", "celery", "1 stalk"],
newArray = [];
while (array.length) {
newArray.push([array.shift(), array.shift()]);
}
console.log(newArray);
I have an array like [1,4,3,1,6,5,1,4,4]
Here Highest element frequency is 3 ,I need to select all elements from array that have 3 frequency like [1,4] in above example.
I have tried with this
var count = {},array=[1,4,3,1,6,5,1,4,4],
value;
for (var i = 0; i < array.length; i++) {
value = array[i];
if (value in count) {
count[value]++;
} else {
count[value] = 1;
}
}
console.log(count);
this will output array element with their frequency , now i need all elements that have highest frequency.
I'd approach this problem as follows.
First, write down how you think the problem can be solved IN ENGLISH, or something close to English (or your native language of course!). Write down each step. Start off with a high-level version, such as:
Count the frequency of each element in the input.
Find the highest frequency.
and so on. At this point, it's important that you don't get bogged down in implementation details. Your solution should be applicable to almost any programming language.
Next flesh out each step by adding substeps. For instance, you might write:
Find the highest frequency.
a. Assume the highest frequency is zero.
b. Examine each frequency. If it is higher than the current highest frqeuency, make it the current highest frequency.
Test your algorithm by executing it manually in your head.
Next, convert what you have written about into what is sometimes called pseudo-code. It is at this point that our algorithm starts to look a little bit like a computer program, but is still easily human-readable. We may now use variables to represent things. For instance, we could write "max_freq ← cur_freq". We can refer to arrays, and write loops.
Finally, convert your pseudo-code into JS. If all goes well, it should work the first time around!
In recent years, a lot of people are jumping right into JavaScript, without any exposure to how to think about algorithms, even simple ones. They imagine that somehow they need to be able to, or will magically get to the point where they can, conjure up JS out of thin air, like someone speaking in tongues. In fact, the best programmers do not instantly start writing array.reduce when confronted with a problem; they always go through the process--even if only in their heads--of thinking about the approach to the problem, and this is an approach well worth learning from.
If you do not acquire this skill, you will spend the rest of your career posting to SO each time you can't bend your mind around a problem.
A proposal with Array.prototype.reduce() for a temporary object count, Object.keys() for getting the keys of the temporary object, a Array.prototype.sort() method for ordering the count results and Array.prototype.filter() for getting only the top values with the most count.
Edit: Kudos #Xotic750, now the original values are returned.
var array = [1, 4, 3, 1, 6, 5, 1, 4, 4],
result = function () {
var temp = array.reduce(function (r, a, i) {
r[a] = r[a] || { count: 0, value: a };
r[a].count++;
return r;
}, {});
return Object.keys(temp).sort(function (a, b) {
return temp[b].count - temp[a].count;
}).filter(function (a, _, aa) {
return temp[aa[0]].count === temp[a].count;
}).map(function (a) {
return temp[a].value;
});
}();
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Bonus with a different attempt
var array = [1, 4, 3, 1, 6, 5, 1, 4, 4],
result = array.reduce(function (r, a) {
r.some(function (b, i) {
var p = b.indexOf(a);
if (~p) {
b.splice(p, 1);
r[i + 1] = r[i + 1] || [];
r[i + 1].push(a);
return true;
}
}) || (
r[1] = r[1] || [],
r[1].push(a)
);
return r;
}, []).pop();
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
you can try this
var input = [1,4,3,1,6,5,1,4,4];
var output = {};
for ( var counter = 0; counter < input.length; counter++ )
{
if ( !output[ input[ counter ] ] )
{
output[ input[ counter ] ] = 0;
}
output[ input[ counter ] ]++;
}
var outputArr = [];
for (var key in output)
{
outputArr.push([key, output[key]])
}
outputArr = outputArr.sort(function(a, b) {return b[1] - a[1]})
now initial values of outputArr are the ones with highest frequency
Here is the fiddle
Check this updated fiddle (this will give the output you want)
var input = [1,4,3,1,6,5,1,4,4];
var output = {}; // this object holds the frequency of each value
for ( var counter = 0; counter < input.length; counter++ )
{
if ( !output[ input[ counter ] ] )
{
output[ input[ counter ] ] = 0; //initialized to 0 if value doesn't exists
}
output[ input[ counter ] ]++; //increment the value with each occurence
}
var outputArr = [];
var maxValue = 0;
for (var key in output)
{
if ( output[key] > maxValue )
{
maxValue = output[key]; //find out the max value
}
outputArr.push([key, output[key]])
}
var finalArr = []; //this array holds only those keys whose value is same as the highest value
for ( var counter = 0; counter < outputArr.length; counter++ )
{
if ( outputArr[ counter ][ 1 ] == maxValue )
{
finalArr.push( outputArr[ counter ][ 0 ] )
}
}
console.log( finalArr );
I would do something like this. It's not tested, but it's commented for helping you to understand my approach.
// Declare your array
var initial_array = [1,4,3,1,6,5,1,4,4];
// Declare an auxiliar counter
var counter = {};
// Loop over the array
initial_array.forEach(function(item){
// If the elements is already in counter, we increment the repetition counter.
if counter.hasOwnProperty(item){
counter[item] += 1;
// If the element is not in counter, we set the repetitions to one
}else{
counter[item] = 1;
}
});
// counter = {1 : 3, 4 : 3, 3 : 1, 6 : 1, 5 : 1}
// We move the object keys to an array (sorting it's more easy this way)
var sortable = [];
for (var element in counter)
sortable.push([element, counter[element]]);
// sortable = [ [1,3], [4,3], [3,1], [6,1], [5,1] ]
// Sort the list
sortable.sort(function(a, b) {return a[1] - b[1]})
// sortable = [ [1,3], [4,3], [3,1], [6,1], [5,1] ] sorted, in this case both are equals
// The elements in the firsts positions are the elements that you are looking for
// This auxiliar variable will help you to decide the biggest frequency (not the elements with it)
higgest = 0;
// Here you will append the results
results = [];
// You loop over the sorted list starting for the elements with more frequency
sortable.forEach(function(item){
// this condition works because we have sorted the list previously.
if(item[1] >= higgest){
higgest = item[1];
results.push(item[0]);
}
});
I'm very much with what #torazaburo had to say.
I'm also becoming a fan of ES6 as it creeps more and more into my daily browser. So, here is a solution using ES6 that is working in my browser now.
The shims are loaded to fix browser browser bugs and deficiencies, which is recommended in all environments.
'use strict';
// Your array of values.
const array = [1, 4, 3, 1, 6, 5, 1, 4, 4];
// An ES6 Map, for counting the frequencies of your values.
// Capable of distinguishing all unique values except `+0` and `-0`
// i.e. SameValueZero (see ES6 specification for explanation)
const frequencies = new Map();
// Loop through all the `values` of `array`
for (let item of array) {
// If item exists in frequencies increment the count or set the count to `1`
frequencies.set(item, frequencies.has(item) ? frequencies.get(item) + 1 : 1);
}
// Array to group the frequencies into list of `values`
const groups = [];
// Loop through the frequencies
for (let item of frequencies) {
// The `key` of the `entries` iterator is the value
const value = item[0];
// The `value` of the `entries` iterator is the frequency
const frequency = item[1];
// If the group exists then append the `value`,
// otherwise add a new group containing `value`
if (groups[frequency]) {
groups[frequency].push(value);
} else {
groups[frequency] = [value];
}
}
// The most frequent values are the last item of `groups`
const mostFrequent = groups.pop();
document.getElementById('out').textContent = JSON.stringify(mostFrequent);
console.log(mostFrequent);
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.4.1/es5-shim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.34.0/es6-shim.js"></script>
<pre id="out"></pre>
you can do like this to find count occurrence each number
var array = [1, 4, 3, 1, 6, 5, 1, 4, 4];
var frequency = array.reduce(function(sum, num) {
if (sum[num]) {
sum[num] = sum[num] + 1;
} else {
sum[num] = 1;
}
return sum;
}, {});
console.log(frequency)
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
I have a data dictionary like this:
var data = {
'text1': 1,
'text2': 2,
'text3': 3,
...
'text20': 20
];
I need to pick a random selection of those keys and then shuffle it's values. In the example, it should write something like this:
> console.log(choose(data, 5));
[ { key: 'text15', value: 8 },
{ key: 'text6', value: 3 },
{ key: 'text3', value: 15 },
{ key: 'text19', value: 6 },
{ key: 'text8', value: 19 } ]
For now I'm extracting the keys into another array and sorting by Math.random() but I'm stuck at swaping the values because no key should have the same value it initially had.
How would you swap key/values here?
Thanks
I put together a possible solution using underscore.js to simplify traversing the object and arrays in a cross browser manner:
var data = {
text1: 1,
text2: 2,
text3: 3,
text4: 4,
text5: 5,
text6: 6,
text7: 7,
text8: 8,
text9: 9,
text10: 10
};
function choose(data, num)
{
var keys = _.sortBy(
_.keys(data),
function(k)
{
return (Math.random() * 3) - 1;
}
),
results = [],
k1, k2;
if (num > keys.length) {
throw new Error('Impossible to retrieve more values than exist');
}
while (results.length < num) {
k1 = k2 || keys.pop();
k2 = keys.pop();
results.push({key:k1, value: data[k2]});
}
return results;
}
console.log(choose(data, 5));
This isn't necessarily an optimal approach but it seems to meet your requirements. I first grab all of the keys and sort them randomly. I then loop through the random keys creating a new object with one key and the following keys value. That way you'll always end up with a different value associated with each key. If you need it to work when the value of num passed in to the function == the number of keys in the data then you'll have to add a little more code - I'll leave that as an exercise for the reader :)
You can have a play with this code on jsfiddle:
http://jsfiddle.net/zVyQW/1/
You could do this:
collect names and corresponding values in two arrays names and values
shuffle both arrays independently of each other
take the first n items of both arrays and combine them
Here’s an example implementation:
Array.prototype.shuffle = function() {
for (var i=this.length-1, j, tmp; i>0; i--) {
j = Math.round(Math.random()*i);
tmp = this[i], this[i] = this[j], this[j] = tmp;
}
return this;
};
function choose(data, number) {
var names = [], values = [], pick = [];
for (var name in data) {
if (data.hasOwnProperty(name)) {
names.push(name);
values.push(data[name]);
}
}
names = names.shuffle(), values = values.shuffle();
for (var i=Math.min(number >>> 0, names.length-1); i>=0; i--) {
pick.push({key: names[i], value: values[i]});
}
return pick;
}
Been a while since this was answered, but I was working on shuffling and found the following to be by far the fastest implementation with an evenly random distribution.
It's fast because it only makes one call to Math.random on each iteration, all the rest is done by property access. It doesn't modify the array, just reassigns values.
function shuffle(a) {
var t, j, i=a.length, rand=Math.random;
// For each element in the array, swap it with a random
// element (which might be itself)
while (i--) {
k = rand()*(i+1)|0;
t = a[k];
a[k]=a[i];
a[i]=t;
}
return a;
}
It uses a combination of three functions (including the Array shuffle prototype method).
Here is the complete code:
var obj = {
"red":"RED",
"blue":"BLUE",
"green":"GREEN",
"yellow":"YELLOW",
"purple":"PURPLE"
};
Array.prototype.shuffle = function(){
for (var i = 0; i < this.length; i++){
var a = this[i];
var b = Math.floor(Math.random() * this.length);
this[i] = this[b];
this[b] = a;
}
}
obj = shuffleProperties(obj); // run shuffle
function shuffleProperties(obj) {
var new_obj = {};
var keys = getKeys(obj);
keys.shuffle();
for (var key in keys){
if (key == "shuffle") continue; // skip our prototype method
new_obj[keys[key]] = obj[keys[key]];
}
return new_obj;
}
function getKeys(obj){
var arr = new Array();
for (var key in obj)
arr.push(key);
return arr;
}
for(key in obj){
alert(key);
}
Check all post,
Best Regards.
Use an implementation of random that randomizes a discrete set of values, such as Math.rand seen here. For each index, randomize Math.rand(index, length-1) to get a list of random indexes, the location off all indices will change.
Say, I have an array that looks like this:
var playlist = [
{artist:"Herbie Hancock", title:"Thrust"},
{artist:"Lalo Schifrin", title:"Shifting Gears"},
{artist:"Faze-O", title:"Riding High"}
];
How can I move an element to another position?
I want to move for example, {artist:"Lalo Schifrin", title:"Shifting Gears"} to the end.
I tried using splice, like this:
var tmp = playlist.splice(2,1);
playlist.splice(2,0,tmp);
But it doesn't work.
The syntax of Array.splice is:
yourArray.splice(index, howmany, element1, /*.....,*/ elementX);
Where:
index is the position in the array you want to start removing elements from
howmany is how many elements you want to remove from index
element1, ..., elementX are elements you want inserted from position index.
This means that splice() can be used to remove elements, add elements, or replace elements in an array, depending on the arguments you pass.
Note that it returns an array of the removed elements.
Something nice and generic would be:
Array.prototype.move = function (from, to) {
this.splice(to, 0, this.splice(from, 1)[0]);
};
Then just use:
var ar = [1,2,3,4,5];
ar.move(0,3);
alert(ar) // 2,3,4,1,5
Diagram:
If you know the indexes you could easily swap the elements, with a simple function like this:
function swapElement(array, indexA, indexB) {
var tmp = array[indexA];
array[indexA] = array[indexB];
array[indexB] = tmp;
}
swapElement(playlist, 1, 2);
// [{"artist":"Herbie Hancock","title":"Thrust"},
// {"artist":"Faze-O","title":"Riding High"},
// {"artist":"Lalo Schifrin","title":"Shifting Gears"}]
Array indexes are just properties of the array object, so you can swap its values.
With ES6 you can do something like this:
const swapPositions = (array, a ,b) => {
[array[a], array[b]] = [array[b], array[a]]
}
let array = [1,2,3,4,5];
swapPositions(array,0,1);
/// => [2, 1, 3, 4, 5]
Here is an immutable version for those who are interested:
function immutableMove(arr, from, to) {
return arr.reduce((prev, current, idx, self) => {
if (from === to) {
prev.push(current);
}
if (idx === from) {
return prev;
}
if (from < to) {
prev.push(current);
}
if (idx === to) {
prev.push(self[from]);
}
if (from > to) {
prev.push(current);
}
return prev;
}, []);
}
You could always use the sort method, if you don't know where the record is at present:
playlist.sort(function (a, b) {
return a.artist == "Lalo Schifrin"
? 1 // Move it down the list
: 0; // Keep it the same
});
Change 2 to 1 as the first parameter in the splice call when removing the element:
var tmp = playlist.splice(1, 1);
playlist.splice(2, 0, tmp[0]);
Immutable version, no side effects (doesn’t mutate original array):
const testArr = [1, 2, 3, 4, 5];
function move(from, to, arr) {
const newArr = [...arr];
const item = newArr.splice(from, 1)[0];
newArr.splice(to, 0, item);
return newArr;
}
console.log(move(3, 1, testArr));
// [1, 4, 2, 3, 5]
codepen: https://codepen.io/mliq/pen/KKNyJZr
EDIT: Please check out Andy's answer as his answer came first and this is solely an extension of his
I know this is an old question, but I think it's worth it to include Array.prototype.sort().
Here's an example from MDN along with the link
var numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
return a - b;
});
console.log(numbers);
// [1, 2, 3, 4, 5]
Luckily it doesn't only work with numbers:
arr.sort([compareFunction])
compareFunction
Specifies a function that defines the sort order. If omitted, the array is sorted according to each character's Unicode code point value, according to the string conversion of each element.
I noticed that you're ordering them by first name:
let playlist = [
{artist:"Herbie Hancock", title:"Thrust"},
{artist:"Lalo Schifrin", title:"Shifting Gears"},
{artist:"Faze-O", title:"Riding High"}
];
// sort by name
playlist.sort((a, b) => {
if(a.artist < b.artist) { return -1; }
if(a.artist > b.artist) { return 1; }
// else names must be equal
return 0;
});
note that if you wanted to order them by last name you would have to either have a key for both first_name & last_name or do some regex magic, which I can't do XD
Hope that helps :)
Try this:
playlist = playlist.concat(playlist.splice(1, 1));
If you only ever want to move one item from an arbitrary position to the end of the array, this should work:
function toEnd(list, position) {
list.push(list.splice(position, 1));
return list;
}
If you want to move multiple items from some arbitrary position to the end, you can do:
function toEnd(list, from, count) {
list.push.apply(list, list.splice(from, count));
return list;
}
If you want to move multiple items from some arbitrary position to some arbitrary position, try:
function move(list, from, count, to) {
var args = [from > to ? to : to - count, 0];
args.push.apply(args, list.splice(from, count));
list.splice.apply(list, args);
return list;
}
Time complexity of all answers is O(n^2) because had used twice spice. But O(n/2) is possible.
Most Perfomance Solution:
Array with n elements,
x is to, y is from
should be n >x && n > y
time complexity should be |y - x|. So its is number of elements that is between from and to.
bestcase: O(1); //ex: from:4 to:5
average : O(n/2)
worthcase : O(n) //ex: from:0 to:n
function reOrder(from,to,arr) {
if(from == to || from < 0 || to < 0 ) { return arr};
var moveNumber = arr[from];
if(from < to) {
for(var i =from; i< to; i++){
arr[i] = arr[i+1]
}
}
else{
for(var i = from; i > to; i--){
arr[i] = arr[i-1];
}
}
arr[to] = moveNumber;
return arr;
}
var arr = [0,1,2,3,4,5,6,7,8,9,10,11,12,13];
console.log(reOrder(3,7,arr));
As a simple mutable solution you can call splice twice in a row:
playlist.splice(playlist.length - 1, 1, ...playlist.splice(INDEX_TO_MOVE, 1))
On the other hand, a simple inmutable solution could use slice since this method returns a copy of a section from the original array without changing it:
const copy = [...playlist.slice(0, INDEX_TO_MOVE - 1), ...playlist.slice(INDEX_TO_MOVE), ...playlist.slice(INDEX_TO_MOVE - 1, INDEX_TO_MOVE)]
I came here looking for a rearranging complete array, I want something like I did below, but found most of the answers for moving only one element from position A to position B.
Hope my answer will help someone here
function reArrangeArray(firstIndex=0,arr){
var a = [];
var b = []
for(let i = 0; i<= (arr.length-1); i++){
if(i<firstIndex){
a.push(arr[i])
}else{
b.push(arr[i])
}
}
return b.concat(a)
}
const arrayToRearrange = [{name: 'A'},{name: 'B'},{name: 'C'},{name: 'D'},{name: 'E'}];
reArrangeArray(2,arrayToRearrange)
// Output
// [
// { name: 'C' },
// { name: 'D' },
// { name: 'E' },
// { name: 'A' },
// { name: 'B' }
// ]
Reorder its work This Way
var tmpOrder = playlist[oldIndex];
playlist.splice(oldIndex, 1);
playlist.splice(newIndex, 0, tmpOrder);
I hope this will work