deconstructing the reduce function in javascript - javascript

With the regular built in reduce function, if you don't assign an initial start value, it starts wrapping over the first 2 array values. Is there a way to do that with a forEach instead of the forLoop I have now? I tried using a forEach but I didn't know how to get it start from arr[1]. If I use a forEach like the 2nd conditional, it gives me 11 instead of 10.
function reduce(arr, callback, start) {
if (start === undefined) {
var current = arr[0];
for (var i = 1; i < arr.length; i++) {
current = callback(current, arr[i]);
}
return current;
}
else {
var current = start;
arr.forEach(function(e) {
current = callback(current, e);
});
return current;
}
}
console.log(reduce([1, 2, 3, 4], function(a, b) {
return a + b;
})); //-> should return 10

Found this polyfill to add reduce to browsers that don't support it.
// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback /*, initialValue*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.reduce called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var t = Object(this), len = t.length >>> 0, k = 0, value;
if (arguments.length == 2) {
value = arguments[1];
} else {
while (k < len && !(k in t)) {
k++;
}
if (k >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = t[k++];
}
for (; k < len; k++) {
if (k in t) {
value = callback(value, t[k], k, t);
}
}
return value;
};
}

Related

Javascript - Permutations remove the duplicates elements

that is found here in stack but i want somes changes.
function perms(data) {
if (!(data instanceof Array)) {
throw new TypeError("input data must be an Array");
}
data = data.slice(); // make a copy
var permutations = [],
stack = [];
function doPerm() {
if (data.length == 0) {
permutations.push(stack.slice());
}
for (var i = 0; i < data.length; i++) {
var x = data.splice(i,1);
stack.push(x);
doPerm();
stack.pop();
data.splice(i, 0, x);
}
}
doPerm();
return permutations;
}
var input = "552".split('');
var result = perms(input);
for (var i = 0; i < result.length; i++) {
result[i] = result[i].join('-');
}
The result of that is :
5-5-2
5-2-5
5-5-2
5-2-5
2-5-5
2-5-5
but , are 3 elements duplicates the result must be :
5-5-2
5-2-5
2-5-5
how can i fix that issue .
Basically, you have one issue,
var x = data.splice(i, 1)[0];
// ^^^ is missing
because you get an array with splicing. The result is a deep nested array with
data.splice(i, 0, x);
This inserts the array later on position i.
For preventing duplicates, you need a check, if the actual value is already inserted in the result set with
permutations.some(function (a) {
return a.every(function (b, j) {
return stack[j] === b;
});
}) || permutations.push(stack.slice());
which test the arrays and if no match, the push is performed.
function perms(data) {
if (!(data instanceof Array)) {
throw new TypeError("input data must be an Array");
}
data = data.slice(); // make a copy
var permutations = [],
stack = [],
hash = Object.create(null);
function doPerm() {
if (data.length == 0) {
permutations.some(function (a) {
return a.every(function (b, j) {
return stack[j] === b;
});
}) || permutations.push(stack.slice());
return;
}
for (var i = 0; i < data.length; i++) {
var x = data.splice(i, 1)[0];
stack.push(x);
doPerm();
stack.pop();
data.splice(i, 0, x);
}
}
doPerm();
return permutations;
}
var input = "552".split('');
var result = perms(input);
for (var i = 0; i < result.length; i++) {
result[i] = result[i].join('-');
}
console.log(result);
Check if array array is present within resulting array before calling .push() using Array.prototype.some(), Array.prototype.join()
function p(a, b, res) {
var b = b || [],
res = res || [],
len = a.length;
if (!len) {
// check if `res` contains `b.join("")`
if (!res.length
|| !res.some(function(n) {
return n.join("") === b.join("")
}))
res.push(b)
} else {
for (var i = 0
; i < len; p(a.slice(0, i).concat(a.slice(i + 1, len))
, b.concat(a[i]), res)
, i++);
}
return res
}
var result = p("552".split(""));
result = result.map(function(res) {
return res.join("-")
});
console.log(result);

Object() without the new keyword or .create method

I was looking on MDN for a polyfill for Array.prototype.includes() and I came across the Object() syntax below:
if (!Array.prototype.includes) {
Array.prototype.includes = function(searchElement /*, fromIndex*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.includes called on null or undefined');
}
//This is the line in question
var O = Object(this);
var len = parseInt(O.length, 10) || 0;
if (len === 0) {
return false;
}
var n = parseInt(arguments[1], 10) || 0;
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
var currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
return true;
}
k++;
}
return false;
};
}
What is Object(this) doing and what is the purpose of this in this case?
Object(...) converts the passed value to an object. It simply returns the value itself if it is already an object, otherwise wit will create a new object and return that.
From the spec:
When Object is called as a function rather than as a constructor, it performs a type conversion.
Example:
var obj = Object("foo");
// same as
// var obj = new String("foo");
what is the purpose of this in this case?
It ensures that the value is an object, not a primitive. The implementation just follows the spec:
Let O be ? ToObject(this value).

Recreating JavaScript Reduce function part 2

This in relation to the reduce function I recreated here, but a different question: Recreating JavaScript's reduce function.
I am reading Eloquent JavaScript and noticed that they recreated the reduce function a slightly different way with less code:
function reduce(array, combine, start) {
var current = start;
for (var i = 0; i < array.length; i++)
current = combine(current, array[i]);
return current;
}
console.log(reduce([1, 2, 3, 4], function(a, b) {
return a + b;
}, 0)); // → 10
I noticed that this only works when there is a start. For example, if I took away the start(0) and it was just:
console.log(reduce([1, 2, 3, 4], function(a, b) {
return a + b;
})); // NaN
It would return NaN. This doesn't make sense to me because the book says:
"If your array contains at least one element, you are allowed to leave off the start argument. The method will take the first element of the array as its start value and start reducing at the second element."
Only when I adjust it with an if statement does it produce "10" with or without a start(0).
function reduce(array, combine, start) {
var current = start;
for (var i = 0; i < array.length; i++)
if(current !==undefined){
current = combine(current, array[i]);
}else{
current=array[i];
}
return current;
}
What am I missing?
Here's how it should be, according to MDN (simplified version here):
function reduce(array, combine, start) {
var current = start;
var i = 0;
if (arguments.length < 2) {
while (array[i] === undefined) {
i ++;
if (array.length >= i) {
throw new Error('Empty array with no initial value');
}
}
current = array[i];
}
for (; i < array.length; ++ i) {
if (array[i] === undefined) continue;
if (current !== undefined) {
current = combine(current, array[i]);
} else {
current=array[i];
}
}
return current;
}

How to eliminate extra matches of element in single array

I'm trying to return the mode of an array. I have an inner loop and outer comparing each element to each other. Array = [5,3,6,3,3,3].
function mode(arr){
for (var i = 0; i < arr.length; i++) {
for (var k = i+1; k < arr.length; k++) {
if (arr[i] == arr[k]) {
modeItems += arr[k];
}else {
otherItems +=arr[i];
}
}
}return modeItems;
}
Result comes back "333333" instead of "3333". I see how this is happening on an excel sheet comparing the 15 total loops aar[i] and arr[k], but I'm not sure what to do.
Below is a hodgepodge answer. My confusion stems from the title
How to eliminate extra matches of element in single array
mixed with this part of the question
I'm trying to return the mode of an array.
Reducing an array to an array of single instances, and an array of all duplicates.
DEMO
var arra = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
function simplify(arr) {
var c = {}, o = [], d = [], i;
for (i = 0; i < arr.length; i++) {
if (!c.hasOwnProperty(arr[i])) {
c[arr[i]] = arr[i];
o.push(arr[i]);
} else {
d.push(arr[i]);
}
}
return {
reduced: o,
duplicates: d
};
}
console.log(simplify(arra));
// >> [object Object] {
// >> duplicates: [2, 3, 3, 4, 4, 4],
// >> reduced: [1, 2, 3, 4]
// >> }
Removing duplicates from an array in place.
DEMO
var arr = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
function elim (arra) {
var c = {}, i = 0;
while (i < arra.length) {
if (c[arra[i]]) {
arra.splice(i, 1);
} else {
c[arra[i]] = true;
i++;
}
}
return arra; // only required for debug.
}
console.log(elim(arr.slice()));
Looping that many times on an array just to find the mode is unnecessary. You can use an object literal as a cache to update your counts. If you want an array minus the mode (or an array with only the mode), you can use .filter afterwards.
Here's a basic implementation. We return null if there is no mode.
DEMO
function findMode (a) {
var cache = {},
len = a.length,
mode,
max = 0,
matched = false;
for (var i = 0; i < len; i++) {
cache[a[i]] = (cache[a[i]] + 1 || 1);
if (cache[a[i]] === max) {
matched = true;
} else if (cache[a[i]] > max) {
max = cache[a[i]];
mode = a[i];
matched = false;
}
}
return (matched ? null : mode);
}
var arr = [5,3,6,3,3,3],
myMode = findMode(arr),
filteredArr = arr.filter(function (e) {
return (e !== myMode);
}),
modeItems = arr.filter(function (e) {
return (e === myMode);
});
console.log(arr); // >> [5,3,6,3,3,3]
console.log(myMode); // >> 3
console.log(filteredArr); // >> [5, 6]
console.log(modeItems); // >> [3, 3, 3, 3]
No mode here:
findMode([5, 7, 5, 7]); // >> null
Something slightly more complex. Returns the mode, mode array, and inverse array in two passes of the original array.
DEMO
var findMode = (function () {
function getMode (a) {
var cache = {},
len = a.length,
mode,
max = 0,
matched = false;
for (var i = 0; i < len; i++) {
cache[a[i]] = (cache[a[i]] + 1 || 1);
if (cache[a[i]] === max) {
matched = true;
} else if (cache[a[i]] > max) {
max = cache[a[i]];
mode = a[i];
matched = false;
}
}
return (matched ? null : mode);
}
function split (arr, mode) {
var set = [],
inverse = [];
if (mode !== null) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === mode) {
set.push(arr[i]);
} else {
inverse.push(arr[i]);
}
}
}
return [set, inverse];
}
return (function (arr) {
var mode = getMode(arr),
lists = split(arr, mode);
return {
mode: mode,
set: lists[0],
inverse: lists[1]
};
});
}());
var info = findMode([5,3,6,3,3,3]),
noMode = findMode([5, 7, 5, 7]);
console.log(info);
console.log(noMode);
Maintain an object array for keeping processed items and ignore the item in the next iterator that are already processed.
function mode(arr) {
var processed = {};
for (var i = 0; i < arr.length; i++) {
for (var k = i + 1; k < arr.length; k++) {
if (arr[i] == arr[k]) {
modeItems += arr[k];
modeItems += !processed[arr[k]] ? arr[k] : '';
processed[arr[k]] = i;
break;
} else {
otherItems += arr[i];
}
}
}
return modeItems;
}
Output: 3,3,3,3
your code is working matching , for every number in the loop , the numbers after the index i+1 :
[5,3,6,3,3,3]
^ ^ //first match
[5,3,6,3,3,3]
^ ^ // match 2
[5,3,6,3,3,3]
^ ^ // match 3
[5,3,6,3,3,3]
^ ^ // match 4
[5,3,6,3,3,3]
^ ^ // match 5
[5,3,6,3,3,3]
^ ^ // match 6
a simple way to work around this issue would be to reset loop with continue if i has already been matched; but it would fail if you had multiple double occurrences..
Let me also add my two cents. This code delete matched items to don't use it again :)
function mode(arr){
var key = arr[0], // it wil be the mode, current value of array
count = 1, // it will be the count of mode value
icount;
for (var i = 0; i < arr.length-count+1; i++) { // there is no need to look any further -
// count is more then rest items
if (!arr[i]) continue;
icount = 1;
for (var k = i+1; k < arr.length; k++) {
if (!arr[k]) continue;
if (arr[i] == arr[k]) { icount++; delete arr[k]; }
}
if (icount > count) { count = icount; key = arr[i]; }
}
if (count == 1) ret = null; // At this moment key - mode. Below output
else { var ret = []; while(count--) ret[count] = key; ret = ret.join();}
return ret;
}

remove string element from javascript array

can some one tell me how can i remove string element from an array
i have google this and all i get is removing by index number
my example :
var myarray = ["xyz" , "abc" , "def"] ;
var removeMe = "abc" ;
myarray.remove(removeMe) ;
consle.log(myarray) ;
this is what i get from the console :
Uncaught TypeError: Object xyz,abc,def has no method 'remove'
​
jsfiddle
Since you're using jQuery
myarray.splice($.inArray("abc", myarray), 1);
EDIT
If the item isn't in the array, this 'one-liner' will likely throw an error. Something a little better
var index = $.inArray("abc", myarray);
if (index>=0) myarray.splice(index, 1);
From https://stackoverflow.com/a/3955096/711129:
Array.prototype.remove= function(){
var what, a= arguments, L= a.length, ax;
while(L && this.length){
what= a[--L];
while((ax= this.indexOf(what))!= -1){
this.splice(ax, 1);
}
}
return this;
}
var ary = ['three', 'seven', 'eleven'];
ary.remove('seven')
or, making it a global function:
function removeA(arr){
var what, a= arguments, L= a.length, ax;
while(L> 1 && arr.length){
what= a[--L];
while((ax= arr.indexOf(what))!= -1){
arr.splice(ax, 1);
}
}
return arr;
}
var ary= ['three','seven','eleven'];
removeA(ary,'seven')
You have to make a function yourself. You can either loop over the array and remove the element from there, or have this function do it for you. Either way, it is not a standard JS feature.
Try like below,
myarray.splice(myarray.indexOf(removeMe),1);
You can add this below script (from MDN) for browsers that doesn't support indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 0) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
more simple solution
var myarray = ["xyz" , "abc" , "def"];
var removeMe = "abc";
var theNewArray = myarray.filter(s => s !== removeMe);
console.log(theNewArray); // will return ["xyz" , "def"]

Categories

Resources