How to split an array into groups [duplicate] - javascript

This question already has answers here:
Split array into chunks
(73 answers)
Closed 7 years ago.
Please consider an array such as :
arrayAll = [1,2,3,4,5,6,7,8,9]
Is there a package that enable to do partitioning to obtain :
arrayALLPartionned = [[1,2,3],[4,5,6],[7,8,9]]
I can see how to do this with a for loop but would appreciate a "pre-made" function if existing.

I think you will have to use a for loop, don't know of any inbuilt functions...
Try this function:
function splitarray(input, spacing)
{
var output = [];
for (var i = 0; i < input.length; i += spacing)
{
output[output.length] = input.slice(i, i + spacing);
}
return output;
}

Here's a recursive solution:
function partition(array, n) {
return array.length ? [array.splice(0, n)].concat(partition(array, n)) : [];
}
This takes advantage of the fact that Array#splice destructively remove the specified items, and returns them as the function value. Note that this will destroy the input array, leaving it empty.

If using Underscore.js, you can implement this with groupBy() and values()
function partition(items, size) {
var result = _.groupBy(items, function(item, i) {
return Math.floor(i/size);
});
return _.values(result);
}
(This is less ugly in CoffeeScript.)
jsFiddle: http://jsfiddle.net/MW3BS/

I've added this solution to #dystroy's jspref here and it appears to run twice as fast as the other solutions. Edit: in Safari & Chrome but not Firefox
Here is functional style solution to add to the mix of answers here.
It is a higher order function called toPartitions which returns a callback for underscore's reduce method or the native array reduce method.
Example usage:
[1,2,3,4,5,6,7,8,9].reduce( toPartitions( 3 ), [] );
The function:
function toPartitions ( size ) {
var partition = [];
return function ( acc, v ) {
partition.push( v );
if ( partition.length === size ) {
acc.push( partition );
partition = [];
}
return acc;
};
}
Like Clojure's partition it will not include a tail partition when there are not enough elements.
In your example you could do:
arrayALLPartionned = arrayAll.reduce( toPartitions( 3 ), [] ) );
If you don't want to use this with reduce, but just have a function which takes an array and partition size you could do:
function partition ( arr, size ) {
return arr.reduce( toPartitions( size ), [] );
}
Therefore the solution would just be:
arrayALLPartionned = partition( arrayAll, 3 );

One more solution, with no external library :
function partition(items, size) {
var p = [];
for (var i=Math.floor(items.length/size); i-->0; ) {
p[i]=items.slice(i*size, (i+1)*size);
}
return p;
}
Demonstration : http://jsfiddle.net/dystroy/xtHXZ/

Prototype has an array.partition function as well as an eachSlice() function. Sounds like eachSlice() is what you're looking for. If you're using jquery, there's a plug in to be able to use prototype functions. Here's a link to it... http://www.learningjquery.com/2009/02/implementing-prototypes-array-methods-in-jquery

You can write your own prototype method to do this
Array.prototype.partition = function(length) {
var result = [];
for(var i = 0; i < this.length; i++) {
if(i % length === 0) result.push([]);
result[result.length - 1].push(this[i]);
}
return result;
};
If you prefer not to add to the native prototype, you can write a simple function:
var partition = function(arr, length) {
var result = [];
for(var i = 0; i < arr.length; i++) {
if(i % length === 0) result.push([]);
result[result.length - 1].push(arr[i]);
}
return result;
};
You can see it in action on this jsFiddle demo.

Related

How to express .filter() function recursively in JavaScript?

Here is a mapping function I was exercising on;
var list = [1,2,3,4,5];
function isOdd(v) {
return v % 2 == 1;
}
function exclude(arr, fn) {
var myList = [];
for (var i = 0; i < arr.length; i++) {
if (fn(arr[i])) {
myList.push(arr[i]);
}
};
return myList;
}
I want to replace for loop with a recursive solution but it doesn't produce a proper array since I started a new list in each function call at line 2. How can I solve it with a recursion? Here is the closest I got;
function exclude(arr, fn) {
let myList = [];
if (arr.length = 1) {
if (fn(arr[0])) {
return myList.push(arr[0]);
}
} else {
return myList.push(exclude(arr.slice(1), fn));
}
}
console.log(exclude(list, isOdd));
Try this one solution. I have changed a bit your implementation.
function exclude(arr, fn, output) {
output || (output = []);
if(!arr.length) {
return output;
}
if (fn(arr[0])) {
output.push(arr[0]);
}
return exclude(arr.slice(1), fn, output);
}
console.log(exclude([1,2,3,4,5,6,7,8,9], function(i) { return i % 2; }));
if (arr.length = 1) {
This assigns 1 to arr.length, effectively trimming the array if there are more than 1 items in it. You probably meant arr.length ===.
Secondly, the Array#push method returns the new length of the array, not the array itself, so where you have:
return myList.push(arr[0]);
You probably want:
myList.push(arr[0]);
return myList;
If you don't want to modify the original array and make copy of the original array on each recursive call, here could be an ugly solution
function exclude(arr, fn, result, index) {
if (!result) {
result = [];
index = -1;
}
index++;
if (index < arr.length && fn(arr[inndex]))
result.push(arr[index]);
if (index === arr.length)
return result;
return exclude(arr, fn, result, index);
}
console.log(exclude([1,2,3,4], function(i){return i%2===0;})); // prints "2,4"
IMHO, your example doesn't really fit with recursion. It is much more readable and less prone to errors to use the for loop here. Recursion can easily mess things up in JS because of contexts and scopes. If you really want to do it as a test case, i recommend you not to transform the array, it will be slow and not of much use. Anyway at the end, you will end with same behaviour as a for loop, but less efficient. here is an example:
var list = [1,2,3,4,5];
function isOdd(v) {
return v % 2 == 1;
}
function exclude(arr, fn, optionalIndex) {
var myList = [];
if(!optionalIndex){
optionalIndex = 0;
}
if(optionalIndex < arr.length){
if(fn(arr[optionalIndex])){
myList.push(arr[optionalIndex]);
}
myList = myList.concat(exclude(arr, fn, optionalIndex + 1));
}
return myList;
}
console.log(exclude(list, isOdd));
It actually would be more interesting for you to try to do it with a real recursion case, for example, using your version with for loop to filter this array with sub-arrays in it:
var list = [1, 2, 3, [0, 1, 2, [0, 10, 20, 30], 4], 5, [1 ,2 ,3]];
Just for fun of it, one line solution:
function exclude(a, fn, c) {
return (c = c || (c !== 0 ? a.length - 1 : c)) >= a.splice(c, fn(a[c]) ? 0:1)*0 ? exclude(a, fn, c - 1) : a;
}
Snippet:
var list = [0,1,2,3,4,5];
function isOdd(v) {
return v % 2 != 0;
}
function exclude(a, fn, c) {
return (c = c || (c !== 0 ? a.length - 1 : c)) >= a.splice(c, fn(a[c]) ? 0:1)*0 ? exclude(a, fn, c - 1) : a;
}
console.log(exclude(list, isOdd));
Since JavaScript doesn't have tail call elimination a recursive solution over a large array will blow your stack. However a functional and recursive approach to the problem would look something like this:
function filter(arr, fn) {
var stopAt = arr.length;
function helper (index, acc) {
return index === stopAt ?
acc :
helper(index+1, fn(arr[index]) ?
acc.concat([arr[index]]) :
acc) ;
}
return helper(0, []);
}
Of course this should never be production code. Having a functional interface while allowing for mutating internal structures is probably the best approach. If you were to look at the source for the functional library Rambda you see that they do mutate internal state.

How to count same items with specail form in a array (javascript)

For example:
input: var arr = ['a','b','c','a-5','c-2'];
output: var result = {'a':6,'b':1,'c':'3'} ;
My solution is:
function countSameItem(arr) {
var counter = {};
for (var i = 0; i < arr.length; i++) {
var item = arr[i].split('-');
if (item.length === 1) {
counter[item] = (counter[item] + 1) || 1;
} else {
counter[item[0]] = (counter[item[0]] + parseInt(item[1]) || parseInt(item[1]));
}
}
return counter;
}
But I want to thought a more consise solution using the lodash
You can do it concisely without lodash:
var result = ['a','b','c','a-5','c-2'].reduce(function(o, s) {
var a = s.split('-').concat(1);
return o[a[0]] = (o[a[0]] || 0) + +a[1], o;
}, Object.create(null));
with lodash you would use the _.reduce function in a similar manner to the way Oriol uses the native reduce function
function countSameItem(arr) {
return _.reduce( arr, function(counter, n, i) {
var narr=n.split('-');
counter[narr[0]] = (counter[narr[0]] || 0) + (1*narr[1] || 1);
return counter;
}, {});
}
counter is the accumulator and what is eventually returned from the function.
n is each element
i is the index of each element.
for each element in the input array counter gets the value returned by the last element that was ran. The third argument in _.reduce gives the initial value of counter.
Using the native implementation is probably better unless you are using lodash for other features and want consistency in the code.
The lodash version of reduce does have the benefit of working on objects as well as arrays but this can be done natively as well by using Object.keys(arr).reduce

Compare array slow

I use a standard way of comparing two arrays, but its as slow as just doing a standard O(n^2)
Can you guys see the problem?
diffArray: function (arr1, arr2, observableArray, mapping) {
//We cant sort orginal arrays
var o = arr1.slice(0);
var n = arr2.slice(0);
// sort both arrays (or this won't work)
var sorter = function (left, right) {
return mapping.key(left) - mapping.key(right);
};
o.sort(sorter); n.sort(sorter);
// declare temporary variables
var op = 0; var np = 0;
var added = []; var removed = [];
// compare arrays and add to add or remove lists
while (op < o.length && np < n.length) {
if (mapping.key(o[op]) < mapping.key(n[np])) {
// push to diff?
removed.push(o[op]);
op++;
}
else if (mapping.key(o[op]) > mapping.key(n[np])) {
// push to diff?
added.push(n[np]);
np++;
}
else {
this.diffMembers(o[op], n[np]);
op++; np++;
}
}
// add remaining items
if (np < n.length)
added = added.concat(n.slice(np, n.length));
if (op < o.length)
removed = removed.concat(o.slice(op, o.length));
ko.utils.arrayForEach(removed, function (item) {
this.itemDeleted(item, mapping);
}.bind(this));
ko.utils.arrayForEach(added, function (item) {
if (observableArray.concurrencyExtendOptions) {
this.itemAdded(observableArray, item, mapping);
}
} .bind(this));
}
Note:
The mapping object is just a helper object the user supplies to compare objects in the array, arr1 and arr2 are standard JS arrays while observableArray is the unwrapped Knockout array
It's based on a C# code example so maybe the sort algorithm in JS isn't as good?
Not sure it will answer you, really, but here is the diff I'm using for arrays:
Array.prototype.diff = function( arr ) {
return arr.map( function( v ) {
if ( !~this.indexOf( v ) ) return v;
}, this ).filter( Boolean );
};
Usage:
arr.diff( otherArr );
PS: Too long to be posted as a comment... Not sure it deserves an answer.
PS2: Original author of the function: #Esailija.

array.indexOf that matches with a function?

Trying to find a clean way to find the index of an array item in JS via a function (specifically for this case, regex-matching a string).
In Ruby, I've been using array.index {|x| fn_to_match x}, is there a JS equivalent of this? indexOf doesn't seem to be usable in this way, unless I'm doing something horribly wrong (very possible)
(FWIW, I'm running this in Node)
I'd make a helper function for that:
function indexOfMatch(array, fn) {
var result = -1;
array.some(function(e, i) {
if (fn(e)) {
result = i;
return true;
}
});
return result;
}
I know this is an old question, but thought I'd should update to say there's now the findIndex() method which returns the index of the first element in the array that satisfies the provided testing function (or -1 if no match found), so you can now use
let index = array.findIndex(fn_to_match);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
Since the normal .indexOf doesn't accept functions, you can overload it like this:
Array.prototype.indexOf = (function(){
var old = Array.prototype.indexOf;
return function(v){
var i, l;
if( typeof v != "function" ) {
return old.apply( this, arguments );
}
for( i = 0, l = this.length; i < l; ++i ) {
if( v.call( this, this[i], i, this ) === true ) {
return i;
}
}
return -1;
};
})();
Then:
var reTest = RegExp.prototype.test;
["ddd", "aaa", "asd"].indexOf( reTest.bind( /asd/ ) );
//2
["ddd", "aaa", "asd"].indexOf( reTest.bind( /ddd/ ) );
//0
Note that this is usable even if you don't wanna overload.. just do Array.prototype.index = ... or whatever name you want for it.
There is no native solution. You may use array.some like this:
var index = -1;
if (searchedArray.some(function(v, i) {
if (/*v is ok*/) { index = i; return true; }
})) {
/* use index */
} else {
/* not found */
}
The most efficient way:
var arr = ['bacon', 'blue', 'beach']
var i = 0
while (!/blue/.test(arr[i])) i++
var match = i < arr.length-1 ? i : null
console.log(i) // 1
Array.forEach could be used but you can't break the loop - it will go on regardless of a match. some() can be used but is likely slower.
You can also create a new method if you're comfortable doing that, or a standalone function:
Array.prototype.search = function(fn){
var index = -1
this.some(function(item, i){
return fn.call(item, item) ? (index = i, true) : false
})
return index
}
var n = arr.search(function(){
return this == 'blue'
}) // 1

How to get object length [duplicate]

This question already has answers here:
Length of a JavaScript object
(43 answers)
Closed 3 years ago.
Is there any built-in function that can return the length of an object?
For example, I have a = { 'a':1,'b':2,'c':3 } which should return 3. If I use a.length it returns undefined.
It could be a simple loop function, but I'd like to know if there's a built-in function?
There is a related question (Length of a JSON object) - in the chosen answer the user advises to transform object into an array, which is not pretty comfortable for my task.
For browsers supporting Object.keys() you can simply do:
Object.keys(a).length;
Otherwise (notably in IE < 9), you can loop through the object yourself with a for (x in y) loop:
var count = 0;
var i;
for (i in a) {
if (a.hasOwnProperty(i)) {
count++;
}
}
The hasOwnProperty is there to make sure that you're only counting properties from the object literal, and not properties it "inherits" from its prototype.
This should do it:
Object.keys(a).length
However, Object.keys is not supported in IE8 and below, Opera and FF 3.6 and below.
Live demo: http://jsfiddle.net/simevidas/nN84h/
Can be done easily with $.map():
var len = $.map(a, function(n, i) { return i; }).length;
Have you taken a look at underscore.js (http://underscorejs.org/docs/underscore.html)? It's a utility library with a lot of useful methods. There is a collection size method, as well as a toArray method, which may get you what you need.
_.size({one : 1, two : 2, three : 3});
=> 3
Summarizing all together, here is a universal function (including ie8 support):
var objSize = function(obj) {
var count = 0;
if (typeof obj == "object") {
if (Object.keys) {
count = Object.keys(obj).length;
} else if (window._) {
count = _.keys(obj).length;
} else if (window.$) {
count = $.map(obj, function() { return 1; }).length;
} else {
for (var key in obj) if (obj.hasOwnProperty(key)) count++;
}
}
return count;
};
document.write(objSize({ a: 1, b: 2, c: 3 }));
// 3
In jQuery i've made it in a such way:
len = function(obj) {
var L=0;
$.each(obj, function(i, elem) {
L++;
});
return L;
}
So one does not have to find and replace the Object.keys method, another approach would be this code early in the execution of the script:
if(!Object.keys)
{
Object.keys = function(obj)
{
return $.map(obj, function(v, k)
{
return k;
});
};
}
Also can be done in this way:
Object.entries(obj).length
For example:
let obj = { a: 1, b: 2, };
console.log(Object.entries(obj).length); //=> 2
// Object.entries(obj) => [ [ 'a', 1 ], [ 'b', 2 ] ]
Here's a jQuery-ised function of Innuendo's answer, ready for use.
$.extend({
keyCount : function(o) {
if(typeof o == "object") {
var i, count = 0;
for(i in o) {
if(o.hasOwnProperty(i)) {
count++;
}
}
return count;
} else {
return false;
}
}
});
Can be called like this:
var cnt = $.keyCount({"foo" : "bar"}); //cnt = 1;
One more answer:
var j = '[{"uid":"1","name":"Bingo Boy", "profile_img":"funtimes.jpg"},{"uid":"2","name":"Johnny Apples", "profile_img":"badtime.jpg"}]';
obj = Object.keys(j).length;
console.log(obj)
For those coming here to find the item count of something that is already a jQuery object:
.length is what you are looking for:
Example:
len = $('#divID').length;
alert(len);
If you want to avoid new dependencies you could make your own smart objects. Of course only if you want to do more that just get it's size.
MyNeatObj = function (obj) {
var length = null;
this.size = function () {
if (length === null) {
length = 0;
for (var key in obj) length++;
}
return length;
}
}
var thingy = new MyNeatObj(originalObj);
thingy.size();
You might have an undefined property in the object.
If using the method of Object.keys(data).length is used those properties will also be counted.
You might want to filter them out out.
Object.keys(data).filter((v) => {return data[v] !== undefined}).length
You may use something like Lodash lib and _.toLength(object) should give you the length of your object
You could add another name:value pair of length, and increment/decrement it appropriately. This way, when you need to query the length, you don't have to iterate through the entire objects properties every time, and you don't have to rely on a specific browser or library. It all depends on your goal, of course.

Categories

Resources