I have array of items with values like below:-
item[0] A quantity[0] 10 Category[0] Alpha itemtype[0] Groceries
item[1] A quantity[1] 15 Category[1] Beta itemtype[1] Toiletries
item[2] B quantity[2] 5 Category[2] Alpha itemtype[2] Stationery
Using Javascript, I wanted to consolidate the quantity for identical items, plus it should only show item type where category is Alpha if there are few identical items. The result of the new arrays should be :
item[0] A quantity[0] 25 category[0] Alpha itemtype[0]Groceries
item[1] B quantity[1] 5 category[1] Alpha itemtype[1]Stationery
for (var i = 0, l = category.length; i < l; i++) {
if (category[i + 1] !== category[i]) {
category.splice(i + 1, 1);
item.splice(i + 1, 1);
quantity[i] = String(+quantity[i] + +quantity[i + 1]);
quantity.splice(i + 1, 1);
itemtype.splice(i + 1, 1);
}
i--; l--;
}
Fiddle
You can also add the separate arrays to a wrapper, and loop over that with forEach (IE9 and above IIRC):
var arrays = [ category, item , quantity, itemtype ];
for (var i = 0, l = category.length; i < l; i++) {
if (category[i + 1] !== category[i]) {
quantity[i] = String(+quantity[i] + +quantity[i + 1]);
arrays.forEach(function (el) { return el.splice(i + 1, 1); });
}
i--; l--;
}
Fiddle
I think it's easier to use array of objects like
var items = [
{item: 'A', quantity: 10, category: 'Alpha', itemtype: 'Groceries'},
{item: 'A', quantity: 15, category: 'Beta', itemtype: 'Toiletries'},
{item: 'B', quantity: 5, category: 'Alpha', itemtype: 'Stationery'}
]
then filter it
var result = [];
for(var i=0; i<items.length; i++){
if (items[i].category == "Alpha"){
result.push(items[i]);
}
}
result is your new array.
Try something like
// create JS-objects to collect the values ...
var i,nam,quant={},cat={},ityp={};
for (i=0; i<item.length; i++) {
nam=item[i];
// initialise the summation variable to zero first:
if (typeof quant[nam]=='undefined') quant[nam]=0;
// do the summation
quant[nam]+=quantity[i];
// initialise the string variables too:
if (typeof ityp[nam]=='undefined') ityp[nam]='';
if (typeof cat[nam]=='undefined') cat[nam]='';
if (category[i]=='Alpha') { // set the variables, if ...
ityp[nam]=itemtype[i];
cat[nam]=category[i];
}
}
// destroy original arrays ...
category=[];item=[];quantity=[];itemtype=[];
// ... and build them up again:
for (i in quant) {
item.push(i);
quantity.push(quant[i]);
category.push(cat[i]);
itemtype.push(ityp[i]);
}
This approach does not rely on any given order of the elements in the arrays.
See here for demo: http://jsfiddle.net/CP2cQ/
Related
I have two arrays like this,
var firstArray = ['one','two','three','four','five','six','seven'];
var secondArray =['1','2','3','4','5','6','7','8'];
I have to insert second array elements into first array like this,
var combinedArray =['one','two','three','1','2','four','five','six','3','4','seven','5','6','7','8']
I know that I could splice and insert at specific index for one element. However I am confused how exactly to achieve this pattern.
Could any one help me out with this?
You could use a pattern for the chunks and slice the wanted length for a new array.
var firstArray = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'],
secondArray = ['1', '2', '3', '4', '5', '6', '7', '8'],
data = [firstArray, secondArray],
pattern = [3, 2],
result = [],
i = 0,
l = data.reduce(function (r, a) { return Math.max(r, a.length); }, 0);
while (i < l) {
pattern.forEach(function (a, j) {
result = result.concat(data[j].slice(i * a, (i + 1) * a));
});
i++;
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can actually splice more than one item:
firstArray.splice(3, 0, "1", "2");
You can create two variables i and j and increment first one by 3 that you will use to slice first array and increment the second one by 2 and you will use that one to slice second array. If the i + 3 > a.length you will concat rest of elements in b array to result.
var a = ['one','two','three','four','five','six','seven'];
var b = ['1','2','3','4','5','6','7','8'];
var r = [], i = 0, j = 0
while(i < a.length) {
r.push(...a.slice(i, i + 3), ...b.slice(j, i + 3 < a.length ? j + 2 : b.length))
i += 3, j += 2
}
console.log(r)
a more granular approach:
var firstArray = ['one','two','three','four','five','six','seven'];
var secondArray =['1','2','3','4','5','6','7','8'];
var combinedArray = flatten(zip(
toGroupsOf(3, firstArray),
toGroupsOf(2, secondArray)
));
console.log(combinedArray);
//a the utilities for that
function isUint(value){
return value === (value >>> 0)
}
function toGroupsOf(length, arrayOrString){
if( !isUint(length) || !length )
throw new Error("invalid length " + JSON.stringify(length));
return Array.from(
{ length: Math.ceil(arrayOrString.length / length) },
(v,i) => arrayOrString.slice(i*length, (i+1)*length)
);
}
function zip(...arraysOrStrings){
var numColumns = arraysOrStrings.length,
lengths = arraysOrStrings.map(item => (item && +item.length) || 0),
x=0, y=0;
return Array.from(
{ length: lengths.reduce((a,b)=>a+b, 0) },
function(v,i){
for(var safety = numColumns+1; safety--;){
if(y < lengths[x])
return arrays[x++][y];
else if(++x >= numColumns)
x=0, ++y;
}
throw new Error("something went wrong, this line should have never been reached");
}
)
}
function flatten(array){
return [].concat.apply([], array);
}
I have a JavaScript object array. When write console.log(myarry) it will show in the console in the below form.
Array[2]
0: Object
one: "one"
1: Object
two: "two"
length: 2
In this array my key and value are same and am trying to get the key or value to a variable and print it. When am trying the below code it showing:
object object
for (var key in myarry) {
alert("Key is " + key + ", value is" + myarry[key]);
}
check this snippet
var obj = [{
"1": "one"
}, {
"2": "two"
}]
obj.forEach(function(item) {
Object.keys(item).forEach(function(key) {
console.log("key:" + key + "value:" + item[key]);
});
});
Hope it helps
Use for-loop instead of for-in to iterate array.
Use Object.keys to get keys of object
var arr = [{
one: 'one'
}, {
two: 'two'
}];
for (var i = 0, l = arr.length; i < l; i++) {
var keys = Object.keys(arr[i]);
for (var j = 0, k = keys.length; j < k; j++) {
console.log("Key:" + keys[j] + " Value:" + arr[i][keys[j]]);
}
}
I think you have two main options to get keys of an object using Object.keys these are: forEach; or a simple for.
1. Use forEach
If you're using an environment that supports the Array features of ES5 (directly or using a shim), you can use the new forEach:
var myarray = [{one: 'one'}, {two: 'two'}];
myarray.forEach(function(item) {
var items = Object.keys(item);
items.forEach(function(key) {
console.log('this is a key-> ' + key + ' & this is its value-> ' + item[key]);
});
});
forEach accepts an iterator function and, optionally, a value to use as this when calling that iterator function (not used above). The iterator function is called for each entry in the array, in order, skipping non-existent entries in sparse arrays. Although
forEach has the benefit that you don't have to declare indexing and value variables in the containing scope, as they're supplied as arguments to the iteration function, and so nicely scoped to just that iteration.
If you're worried about the runtime cost of making a function call for each array entry, don't be; technical details.
2. Use a simple for
Sometimes the old ways are the best:
var myarray = [{one: 'one'}, {two: 'two'}];
for (var i = 0, l = myarray.length; i < l; i++) {
var items = myarray[i];
var keys = Object.keys(items);
for (var j = 0, k = keys.length; j < k; j++) {
console.log('this is a key-> ' + keys[j] + ' & this is its value-> ' + items[keys[j]]);
}
}
Depending on your construction, you can do
const arr = [{ key1: 'val1' }, { key2: 'val2' }]
arr.forEach((a, i) =>
console.log(i, [{ key: Object.keys(a) }, { val: Object.values(a) }])
)
and to answer your question
arr.forEach((a, i) =>
alert("Key is "+ Object.keys(a) + ", value is " + Object.values(a))
)
am trying to get the key or value to a variable and print it.
then you could
var myarry = [{ one: 'one' }, { two: 'two' }];
for (var key in myarry) {
var value = myarry[key];
console.log(key, value)
}
you can do it in this way
const a = [{ one: 'one' }, { two: 'two' }];
a.forEach(function(value,key) {
console.log(value,key);
});
You can take key and value in a variable and use them.
Here's an interesting way to do it.
const arr = [{ one: 'one' }, { two: 'two' }];
Object.entries(arr).forEach(([_, obj]) => {
const key = Object.keys(obj)[0];
console.log(`Key is ${key}, value is ${obj[key]}.`);
});
I have a structure of the form:
var circle = {
'one': {items: []},
'two': {items: []},
'three': {items: []},
'four': {items: []}
};
Each items array should hold 10 unique divs, like this:
circle.one.items array should hold:
<div className="item item-1">1</div>
...
<div className="item item-10">10</div>
...
circle.four.items array should hold:
<div className="item item-31">31</div>
...
<div className="item item-40">40</div>
And I'm using the structure like this:
<div className="circle-one">
{circle.one.items}
</div>
How do I populate the items arrays with those divs?
You could use an array and loop the array for the items.
var circle = { 'one': { items: [] }, 'two': { items: [] }, 'three': { items: [] }, 'four': { items: [] } };
['one', 'two', 'three', 'four'].forEach(function (k, i) {
for (var j = 1; j <= 10; j++) {
circle[k].items.push('<div className="item item-' + (i * 10 + j) + '">' + (i * 10 + j) + '</div>');
}
});
console.log(circle);
Given you have you starting object, then a simple nested loop would work just fine:
var keys = ["one","two","three","four"];
for (var i = 0; i < keys.length; i++) {
for (var j = 0; j < 10; j++) { // Note: you might want to avoid the magic number here
circle[keys[i]].items.push(createDiv(i * 10 + j + 1));
}
}
where createDiv is a function that takes the number for your item-xx and returns the actual div you want.
The one thing to note here is that I have defined an array with the keys to your object in the order that I want them. You should not rely on, for example Object.keys returning the keys in any defined order.
Not sure if you wanted those divs as strings. Anyway you can update populateItems function below to return what you want.
var mapping = { one:1, two:2, three:3, four: 4};
function populateItems(n) {
var output = [];
for (var i = 1; i <= 10; i++) {
var curr = i+(n-1)*10;
output.push('<div className="item item-'+curr+'">+'curr+'</div>');
}
return output;
}
for (p in circle) {
circle[p].items = populateItems(mapping[p]);
}
if you use underscore/lodash you could do this:
_.each(circle, (obj) => {
obj.items = _.map(_.range(10), (n) => {
return <div className={'item item'+n}>n</div>
});
});
my variable naming is pretty terrible btw!
I have the following object:
{ apple: 'banana',
banana: [ 'pear', 'apple' ],
melon: 'apple',
grapes: 'peach',
carrot: 'apple',
peach: 'grapes' }
I am basically tying to find any 'circular references', for example:
apple: 'banana',
banana: ['apple']
and
grapes: 'peach',
peach: 'grapes'
I've spent ages and have tried a number of different approaches, including copying the key and values into a new array, sorting and trying to match - now I'm not even sure what the best way to tackle this is.
Edit: Thanks to everyone for their help. I think it wasn't quite clear with my original question. I was only wanting to identify the case where there exists a reference in both directions. So apple->banana, banana<-apple and grapes->peach, peach<-grapes should match. But melon->apple, banana->apple and carrot->apple should not match at all.
I've got it working with the following (fairly disgraceful) code:
var data = { apple: 'banana',
banana: ['test', 'apple'],
melon: 'apple',
grapes: 'peach',
carrot: 'apple',
peach: 'grapes' };
var arr = [], arr2 = [], u = {}
//Iterate over object 'data' and create an array of arrays - sorted alphabetically
for (var item in data) {
var val = data[item];
if (Array.isArray(val)) {
for (var i = 0; i < val.length; ++i) {
arr.push(new Array(item, val[i]).sort())
}
} else {
arr.push(new Array(item, val).sort())
}
}
//Iterate of arr and look for any matches..
for(var i = 0, l = arr.length; i < l; ++i){
if(u.hasOwnProperty(arr[i])) {
arr2.push(arr[i]);
}
u[arr[i]] = 1;
}
console.log('Matches found: ' + arr2)
//prints: 'Matches found: [ [ 'apple', 'banana' ], [ 'grapes', 'peach' ] ]
Here's one approach in a working snippet:
var data = { apple: 'banana',
banana: [ 'pear', 'apple' ],
melon: 'apple',
grapes: 'peach',
carrot: 'apple',
peach: 'grapes' };
for (var item in data) {
var val = data[item];
if (Array.isArray(val)) {
for (var i = 0; i < val.length; i++) {
if (val[i] in data) {
document.write("circular reference for '" + val[i] + "' in " + item + ":[" + val[i] + "]<br>" );
}
}
} else {
if (val in data) {
document.write("circular reference for '" + val + "' in " + item + ":" + val + "<br>");
}
}
}
It generates this output:
circular reference for 'banana' in apple:banana
circular reference for 'apple' in banana:[apple]
circular reference for 'apple' in melon:apple
circular reference for 'peach' in grapes:peach
circular reference for 'apple' in carrot:apple
circular reference for 'grapes' in peach:grapes
Do you just want direct links? Just check to see if any of the values are keys and if so, if they point to the original key.
_.mapObject(fruit, function(key, val) {
if(fruit[val] && (fruit[val] === key || fruit[val].includes(key))){
console.log(key + ':' + val + ' match!');
}
});
Do you want any circular references? You need a 'visited' array. You're essentially trying to do graph traversal so you can take a look at canonical examples like Dijkstra's.
None language specific approach
Keep a multi-dimensional array/map of keys/values. (Outer array elements = each key name, Inner array elements = values for key)
// Psuedo-Code
// Test: If any element in the outer array exists with the the inner array, check // for self within each inner key's inner array
isCircular(JSON Object) {
// Assume No Circular Reference
var isCircular = false;
// Check all the Keys for Circular references
nextKey = firstKey;
while (nextKey != null)
// Setup loop
var parent = nextKey;
var child = null;
foreach child in parent.values {
// Check the child.value for parent
foreach value in child.value {
// If parent exists, there is a circular reference
if (value == parent) isCircular = true; // CIRCULAR REFERENCE
}
}
nextKey++; // Next Element
}
return isCircular;
}
I have an array that is sorted in the following way
var items = [2.99, 5.99, 23.99, 1.99];
items.sort(function(a,b) { return a - b;});
This outputs the following:
[1.99, 2.99, 5.99, 23.99]
But I need a way to sort it but keep an index of the original index, e.g.
[3: 1.99, 0: 2.99, 1: 5.99, 2:23.99]
Any help would be appreciated.
Map it to an array of objects.
So in the resulting array, each member is an object with an n property that holds the number, and an i property that holds the original index.
You can then iterate that array and get the data like normal.
var items = [2.99, 5.99, 23.99, 1.99];
var arr_of_objs = items.map(function(n, i) {
return { n:n, i:i };
}).sort(function(a, b) {
return a.n - b.n;
});
arr_of_objs.forEach(function(obj, i) {
this.textContent += "number: " + obj.n + ", orig idx: " + obj.i + ", new idx: " + i + "\n";
}, document.querySelector("pre"));
<pre></pre>
var items = [2.99, 5.99, 23.99, 1.99];
var sortable = [];
for (var i = 0; i < items.length; i++) {
sortable.push([i, items[i]]);
}
sortable.sort(function(a, b) {
return a[1] - b[1]
});
console.log(sortable);
Unfortunately it is not possible in JS get sorting in this case. JS understands array only as [0: 1.99, 1:2.99, 3:23.99] -- you cannot change order of indexes. But you can use array of arrays or array of object to solve the problem.
var items = [2.99, 5.99, 23.99, 1.99];
function PreserveKeysSorting(arr) {
var arr = arr
obj = [];
for(i in arr) {
obj.push({index: i, value: arr[i]});
}
obj.sort(function(a,b) { return a.value - b.value;});
return obj;
}
console.log(items);
console.log(PreserveKeysSorting(items));
Live Demo -- http://jsfiddle.net/u1g0xsap/1/
The array that you want as a result is not valid, but you can do something like this:
First make an array that contains objects that persists the index:
var itemsObj = [];
items.forEach(function(value, index) {
itemsObj.push({
value: value,
index: index
});
});
Then you can sort them like this:
items.sort(function(a,b) { return a.value - b.value;});
and you will get an arary of objects like this
[{index:3, value: 1.99}, {index: 0, value: 2.99}, {index: 1, value: 5.99}, {index:2, value:23.99}]
Hardcode the index into the array:
var items = [2.99, 5.99, 23.99, 1.99]
var itemsWithIndex = [];
for (i=0; i<items.length; i++) { itemsWithIndex[i] = [i+1, items[i]]; }
itemsWithIndex.sort(function(a,b) { return a[1]-b[1]; });
Note that an auxiliary variable (itemsWithIndex) was added for clarity, but you can also just update the original array:
var items = [2.99, 5.99, 23.99, 1.99]
for (i=0; i<items.length; i++) { items[i] = [i+1, items[i]]; }
items.sort(function(a,b) { return a[1]-b[1]; });
You could use two arrays and indexOf() method:
// Variables
var items = items_sort = [2.99, 5.99, 23.99, 1.99];
var order = new Array();
// Sort array
items_sort.sort(function(a,b) { return a - b;});
// Get order
for (i = 0; i < items.length; i++) {
order[i] = items.indexOf(items_sort[i]);
}