Related
In Python, I can overwrite elements in an array using slicing syntax and passing a step argument.
For example:
alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
alist[::2] = ["foo", "foo", "foo", "foo", "foo"]
print(alist) # ['foo', 2, 'foo', 4, 'foo', 6, 'foo', 8, 'foo', 10]
Is there a way to mimic this behavior in JavaScript?
You can implement such a function yourself with a for loop.
var alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var alist2 = ["foo", "foo", "foo", "foo", "foo"]
function overwrite(arr, arr2, step){
for(let i = 0, j = 0; i < arr.length && j < arr2.length; i += step, j++){
arr[i] = arr2[j];
}
}
overwrite(alist, alist2, 2);
console.log(alist);
You can use map and return an element from the second list on every even iteration.
const alist = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const blist = ["foo", "foo", "foo", "foo", "foo"];
const clist = alist.map((e,i) => i%2==0?blist[i/2]:e);
console.log (clist)
Let me know if this works for you:
function range(from, to){
let f = from, t = to;
if(t === undefined){
t = from; f = 0;
}
for(var i=f,r=[]; i<=t; i++){
r.push(i);
}
return r;
}
function step(a, num, b){
const r = b.slice();
for(let i=num-1,l=a.length; i<l; i+=num){
if(!a.hasOwnProperty(i)){
break;
}
r.splice(i, 0, a[i]);
}
return r;
}
const aList = range(1, 10), bList = ['foo', 'bar', 'foo', 'bar', 'foo', 'bar'];
console.log(step(aList, 2, bList)); console.log(step(aList, 3, bList));
I working on the Sudoku puzzle, the following code works but it's easy to see that there is a lot of duplicated code. How can I optimize it? Thanks
Problem: getSection: This function should accept three arguments: a sudoku grid, and an x and y coordinate for one of the puzzle's 3x3 subgrids. The function should return an array with all the numbers in the specified subgrid.
Input example:
var puzzle = [[ 8,9,5, 7,4,2, 1,3,6 ],
[ 2,7,1, 9,6,3, 4,8,5 ],
[ 4,6,3, 5,8,1, 7,9,2 ],
[ 9,3,4, 6,1,7, 2,5,8 ],
[ 5,1,7, 2,3,8, 9,6,4 ],
[ 6,8,2, 4,5,9, 3,7,1 ],
[ 1,5,9, 8,7,4, 6,2,3 ],
[ 7,4,6, 3,2,5, 8,1,9 ],
[ 3,2,8, 1,9,6, 5,4,7 ]];
Output:
getSection(puzzle, 0, 0);
// -> [ 8,9,5,2,7,1,4,6,3 ]
Solution:
function getSection(arr, x, y) {
var section = [];
if (y === 0) {
arr = arr.slice(0, 3);
if (x === 0) {
arr.forEach(function (element) {
section.push(element.slice(0, 3));
})
} else if (x === 1) {
arr.forEach(function (element) {
section.push(element.slice(3, 6));
})
} else {
arr.forEach(function (element) {
section.push(element.slice(6, 9));
})
}
}
if (y === 1) {
arr = arr.slice(4, 7);
if (x === 0) {
arr.forEach(function (element) {
section.push(element.slice(0, 3));
})
} else if (x === 1) {
arr.forEach(function (element) {
section.push(element.slice(3, 6));
})
} else {
arr.forEach(function (element) {
section.push(element.slice(6, 9));
})
}
}
if (y === 2) {
arr = arr.slice(6, 9);
if (x === 0) {
arr.forEach(function (element) {
section.push(element.slice(0, 3));
})
} else if (x === 1) {
arr.forEach(function (element) {
section.push(element.slice(3, 6));
})
} else {
arr.forEach(function (element) {
section.push(elemet.slice(6, 9));
})
}
}
var subgrid = section.reduce(function (a, b) {
return a.concat(b);
},
[]
);
return subgrid;
}
console.log(getSection(puzzle, 0, 0));
// // -> [ 8,9,5,2,7,1,4,6,3 ]
console.log(getSection(puzzle, 1, 0));
// -> [ 7,4,2,9,6,3,5,8,1 ]
Here's my take using ES6
const puzzle = [
[8, 9, 5, 7, 4, 2, 1, 3, 6],
[2, 7, 1, 9, 6, 3, 4, 8, 5],
[4, 6, 3, 5, 8, 1, 7, 9, 2],
[9, 3, 4, 6, 1, 7, 2, 5, 8],
[5, 1, 7, 2, 3, 8, 9, 6, 4],
[6, 8, 2, 4, 5, 9, 3, 7, 1],
[1, 5, 9, 8, 7, 4, 6, 2, 3],
[7, 4, 6, 3, 2, 5, 8, 1, 9],
[3, 2, 8, 1, 9, 6, 5, 4, 7]
];
const GRID_SIZE = 3;
function getOffset(coordinate) {
const start = coordinate * GRID_SIZE;
const end = start + GRID_SIZE;
return [start, end];
}
function getSection(arr, x, y) {
const yOffset = getOffset(y);
const xOffset = getOffset(x);
const elements = arr.slice(...yOffset);
return elements
.map(element => element.slice(...xOffset))
.reduce((subgrid, grid) => [...subgrid, ...grid], []);
}
console.log(getSection(puzzle, 0, 0));
// // -> [ 8,9,5,2,7,1,4,6,3 ]
console.log(getSection(puzzle, 1, 0));
// -> [ 7,4,2,9,6,3,5,8,1 ]
I assume your x and y will not exceed your array length. Here's the simplest way to achieve the solution.
function getSection(arr, x, y) {
var GRID_SIZE = 3;
var indexX = x*GRID_SIZE;
var indexY = y*GRID_SIZE;
var results = [];
for(var i = indexY; i< indexY+GRID_SIZE; i++){
results = results.concat(puzzle[i].slice(indexX, indexX+GRID_SIZE));
}
return results;
}
console.log(getSection(puzzle, 0, 0));
// // -> [ 8,9,5,2,7,1,4,6,3 ]
console.log(getSection(puzzle, 1, 0));
// -> [ 7,4,2,9,6,3,5,8,1 ]
Not as elegant as #nutboltu but almost as concise.
function getSection(arr, x, y) {
var section = [];
z = (y===0?0:y+y+2);
arr = arr.slice(z, z+3);
arr.forEach(function (element) {
section.push(element.slice(z, z+3));
})
var subgrid = section.reduce(function (a, b) {
return a.concat(b);
},
[]
);
return subgrid;
}
$(".search").keyup(function(){
var val = this.value;
$.ajax({
type: "POST",
url: "search?entered=" + val,
beforeSend: function(){
$(".search").css("background","#FFF");
},
success: function(data){
for (var i = 0; i < data.length; i++) {
$(".suggesstions").append("<ul>"+data[i]["category"]+" "+data[i]["productTitle"]+"</ul>");
}
}
});
});
Here is my code,
I want to remove duplicate entries from list and append to.
I modified the code with remove duplicate value based on productTitle.
success: function(data){
var array = [],
Finalresult = [];
$.each(data, function (index, value) {
if ($.inArray(value.productTitle, array) == -1) {
array.push(value.productTitle);
Finalresult.push(value);
}
});
for (var i = 0; i < Finalresult.length; i++) {
$(".suggesstions").append("<ul>"+Finalresult[i]["category"]+" "+Finalresult[i]["productTitle"]+"</ul>");
}
console.log(Finalresult);
}
First, you have to remove all duplicate entries from array , like this
var myArr = [2, 5, 5, 7, 7, 8, 9, 9, 9, 1, 3, 3, 4, 5];
var newArr = $.unique(myArr.sort()).sort();
for (var i = 0; i < newArr.length; i++) {
//your code
}
One Liner
var arrOutput = Array.from(new Set([1,2,3,4,5,5,6,7,8,9,6,7]));
alert(arrOutput);
let myArray = [2, 5, 5, 7, 7, 8, 9, 9, 9, 1, 3, 3, 4, 5];
let arrayOutput = [];
myArray?.map((c) => {
if (!arrayOutput.includes(c)) {
arrayOutput.push(c);
}
});
console.log(arrayOutput)
let myArray = [2, 5, 5, 7, 7, 8, 9, 9, 9, 1, 3, 3, 4, 5];
let arrayOutput = [];
myArray?.map((c) => {
(!(arrayOutput.indexOf(c) > -1)) ? arrayOutput.push(c) : null;
});
console.log(arrayOutput)
Node.js app, writing validation tests. Given the following:
var obj = { foo: null, bar: null, baz: null},
values = [ 0, 1];
I need to create n number of objects to account for every property being assigned every combination of possible values, to represent every possible use case. So for this example, the output should be 2^3=8 objects, e.g.
[
{ foo: 0, bar: 0, baz: 0},
{ foo: 0, bar: 1, baz: 0},
{ foo: 0, bar: 1, baz: 1},
{ foo: 0, bar: 0, baz: 1},
{ foo: 1, bar: 0, baz: 0},
{ foo: 1, bar: 1, baz: 0},
{ foo: 1, bar: 1, baz: 1},
{ foo: 1, bar: 0, baz: 1},
]
Underscore or lodash or other libraries are acceptable solutions. Ideally, I would like something like so:
var mapUseCases = function(current, remaining) {
// using Underscore, for example, pull the current case out of the
// possible cases, perform logic, then continue iterating through
// remaining cases
var result = current.map(function(item) {
// perform some kind of logic, idk
return magic(item);
});
return mapUseCases(result, _.without(remaining, current));
}
var myValidationHeadache = mapUseCases(currentThing, somethingElse);
Pardon my pseudocode, I think I broke my brain. ¯\_(ツ)_/¯
Solution for any object length and any values.
Please note, undefined values do not show up.
function buildObjects(o) {
var keys = Object.keys(o),
result = [];
function x(p, tupel) {
o[keys[p]].forEach(function (a) {
if (p + 1 < keys.length) {
x(p + 1, tupel.concat(a));
} else {
result.push(tupel.concat(a).reduce(function (r, b, i) {
r[keys[i]] = b;
return r;
}, {}));
}
});
}
x(0, []);
return result;
}
document.write('<pre>' + JSON.stringify(buildObjects({
foo: [0, 1, 2],
bar: [true, false],
baz: [true, false, 0, 1, 42]
}), 0, 4) + '</pre>');
One way is to count from "000" to "999" in a values.length-based system:
keys = ['foo','bar','baz']
values = ['A', 'B']
width = keys.length
base = values.length
out = []
for(var i = 0; i < Math.pow(base, width); i++) {
var d = [], j = i;
while(d.length < width) {
d.unshift(j % base)
j = Math.floor(j / base)
}
var p = {};
for(var k = 0; k < width; k++)
p[keys[k]] = values[d[k]]
out.push(p)
}
document.write('<pre>'+JSON.stringify(out,0,3))
Update for products:
'use strict';
let
keys = ['foo', 'bar', 'baz'],
values = [
['A', 'B'],
['a', 'b', 'c'],
[0, 1]
];
let zip = (h, t) =>
h.reduce((res, x) =>
res.concat(t.map(y => [x].concat(y)))
, []);
let product = arrays => arrays.length
? zip(arrays[0], product(arrays.slice(1)))
: [[]];
let combine = (keys, values) =>
keys.reduce((res, k, i) =>
(res[k] = values[i], res)
, {});
let z = product(values).map(v => combine(keys, v));
z.map(x => document.write('<pre>'+JSON.stringify(x)+'</pre>'))
This is a non-recursive version of what you want:
function createRange(keys, values) {
if (typeof values[0] !== typeof [])
values = keys.map(k => values);
var pointer = {};
var repeats = 1;
keys.forEach((k, i) => {
var vLen = values[i].length;
repeats *= vLen;
pointer[k] = {
get value() {
return values[i][pointer[k].current]
},
current: 0,
period: Math.pow(vLen, i),
inc: function() {
var ptr = pointer[k];
ptr.current++;
if (ptr.current < vLen) return;
ptr.current = 0;
if (i + 1 === keys.length) return;
var nk = keys[i + 1];
pointer[nk].inc()
}
};
});
var result = [];
for (var i = 0; i < repeats; i++) {
var o = {};
result.push(o);
keys.forEach(k => o[k] = pointer[k].value)
pointer[keys[0]].inc();
}
return result;
}
var objKeys = ['u', 'v', 'w', 'x', 'y', 'z'];
var objValues = [
['1', '2', '3'],
['a', 'b', 'c'],
['foo', 'bar', 'baz'],
[1, 3, 2],
['test', 'try', 'catch'],
['Hello', 'World'],
];
var range = createRange(objKeys, objValues);
range.map(v => document.write(JSON.stringify(v).big()))
What is the cleanest way to reduce those array ?
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5, ...]
v: [10,10,10, 5, 10 ...]
}
For each id there is a v corresponding. What I want is sum up v for each id. In this example the result should be
data = {
id: [1, 3, 4, 5, ...]
v: [30, 15, ...]
}
I would go for the Array.prototype.reduce() ,simple and elegant solution
var ids = [1, 1, 1, 3, 3, 3, 3, 4, 5, 6, 6, 6],
v = [10, 10, 10, 5, 10, 10, 10, 404, 505, 600, 60, 6],
data = {};
data.v = [];
data.ids = ids.reduce(function(a, b, index) {
if (a.indexOf(b) < 0) a.push(b);
if (!data.v[a.indexOf(b)]) data.v[a.indexOf(b)] = 0;
data.v[a.indexOf(b)] += v[index];
return a;
}, []);
https://jsfiddle.net/2ssbngLr/
One way of doing this, given two arrays of equal length would be to map/reduce them:
const ids = [1, 1, 1, 3, 3];
const vs = [10,10,10,5,10];
const reduced = ids
.map((val, i) => ({ id: val, value: vs[i] }))
.reduce((agg, next) => {
agg[next.id] = (agg[next.id] || 0) + next.value;
return agg;
}, {});
console.log(reduced);
// Object {1: 30, 3: 15}
Working example: https://jsfiddle.net/h1o5rker/1/
I think it can be accomplished with reduce
var data = {
id: [1, 1, 1, 3, 3],
v: [10, 10, 10, 5, 10]
}
var sumsObjs = data.v.reduce(function(sum, val, index) {
var id = data.id[index];
if (sum[id] !== undefined) {
sum[id] = sum[id] + val;
} else {
sum[id] = val;
}
return sum;
}, {});
console.log(sumsObjs);
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11]
},
_v = data.v, vinit;
document.write(data.v+'<br>');
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
};
document.write(data.v);
var data={
id: [1,1,1,10,123,4531],
v:[123,123,53,223,11,11,11,...]
},
_v = data.v, vinit;
for(var i=0;i<_v.length;i++){
vinit = _v[i];
for(var j=i+1; j<=_v.length;j++){
if(_v[j]===vinit){
delete _v[j];
}
}
}
the above code is just for the v but you can simultaneously reduce the repeating elements for id too by introducing some more variables
in the snippet you can see that there are the extra commas in the second line which shows that those elements were deleted
If the ids are always in order, a simple for loop can solve it. There is no need to get overly complicated.
data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 1, 2, 3, 4]
};
var result = {
id: [],
v: []
};
(function() {
var ids = data.id,
vals = data.v,
lastId = ids[0],
runningTotal = vals[0];
for (var i = 1; i < ids.length; i++) {
if (lastId === ids[i]) {
runningTotal += vals[i];
}
if (lastId !== ids[i] || i + 1 === ids.length) {
result.id.push(lastId);
result.v.push(runningTotal);
lastId = ids[i];
runningTotal = vals[i];
}
}
}());
console.log(result);
Some people have posted some good solutions so far, but I haven't really seen one that does exactly what you're looking for. Here is one that takes your specific object and returns an object of the same format, but meeting your requirements and reduced.
// Your data object
data = {
id: [1, 1, 1, 3, 3],
v: [10,10,10, 5, 10]
}
// Assuming obj consists of `id` and `v`
function reduce(obj){
// We create our reduced object
var reducedObj = {
id: [],
v: []
}
// Next we create a hash map to store keys and values
var map = {};
for(var i=0; i<obj.id.length; ++i){
// If this key doesn't exist, create it and give it a value
if(typeof map[parseInt(obj.id[i])] === 'undefined'){
map[parseInt(obj.id[i])] = 0;
}
// Sum all of the values together for each key
map[parseInt(obj.id[i])] += parseInt(obj.v[i]);
}
// Now we map back our hashmap to our reduced object
for(var ele in map){
reducedObj.id.push(ele);
reducedObj.v.push(map[ele]);
}
// Return our new reduced object
return reducedObj;
}
var myReducedObject = reduce(data);
console.log(myReducedObject);
Working Fiddle
This is a solution for ordered id with Array.prototype.reduce().
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
},
result = { id: [], v: [] };
data.id.reduce(function (r, a, i) {
if (r === a) {
result.v[result.v.length - 1] += data.v[i];
} else {
result.id.push(a);
result.v.push(data.v[i]);
}
return a;
}, -1);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Or a in situ version
var data = {
id: [1, 1, 1, 3, 3, 4, 5, 5, 5],
v: [10, 10, 10, 5, 10, 7, 8, 10, 13]
};
void function (d) {
var i = 1;
while (i < d.id.length) {
if (d.id[i - 1] === d.id[i]) {
d.id.splice(i, 1);
d.v[i - 1] += d.v.splice(i, 1)[0];
continue;
}
i++;
}
}(data);
document.write('<pre>' + JSON.stringify(data, 0, 4) + '</pre>');