Dictionary with arrays of keys and values - javascript

This question is in regards to javascript or jQuery, whichever will get the job done better.
What I want to do is create an object similar to the following:
var prodItems = [
{
"product": "prod1",
"item": ["prod1Item1", "prod1Item2"]
},
{
"product": "prod2",
"item": ["prod2Item1", "prod2Item2", "prod2Item3", "prod2Item4"]
}
];
with this I can access the members like this:
prodItems[1]["product"] is "prod2"
prodItems[1]["item"][0] is "prod2Item1"
I would like to create this list dynamically and I am stumbling with the syntax, something like:
var menuItems;
menuItems.product[0] = "prod1";
menuItems.product[0].item[0] = "prod1Item1";
Can someone please give me some guidance on how I can do this?
Edit, i want to create a function with something like
returnDict("prod2", "prod2Item3")
this will rearrange it like so:
prodItems = [
{
"product": "prod2",
"item": ["prod2Item3", "prod2Item1", "prod2Item2", "prod2Item4"]
},
{
"product": "prod1",
"item": ["prod1Item1", "prod2Item2"]
}
];

My "guidance" on constructing the object would be to avoid this style of inserting each string separately:
menuItems.product[0].product = "prod1";
menuItems.product[0].item[0] = "prod1Item1";
because this involves a lot of writing the same thing over and over, which is more error-prone and less readable/maintainable. I would prefer inserting more coarse-grained objects:
menuItems.product[0] = {
product: "prod1",
item: ["prod1Item1"];
}
Edit: Your edit is asking a completely different question, but it sounds like what you want to do is sort the elements of prodItems based on their "product" properties, then do the same thing for the "items" array inside the elements.
I think the simplest way to do this would be to use Array.sort() with a custom comparison function that returns -1 on the element you want to see at the top. Something like this (hastily written and untested):
function returnDict(product, item) {
prodItems = prodItems.sort(function(a, b) {
if(a.product === product) {
return -1;
} else if(b.product === product) {
return 1;
} else {
return 0;
}
});
prodItems[0].items = prodItems[0].items.sort(function(a, b) {
if(a === item) {
return -1;
} else if(b === item) {
return 1;
} else {
return 0;
}
});
return prodItems;
}

var menuItems = [];
menuItems.push({product:"prod1",item:[]})
menuItems[menuItems.length-1].item.push("product1Item1")
menuItems[menuItems.length-1].item.push("product1Item2")
menuItems.push({product:"prod2",item:[]})
menuItems[menuItems.length-1].item.push("product2Item1")
menuItems[menuItems.length-1].item.push("product2Item2")
menuItems[menuItems.length-1].item.push("product2Item3")
menuItems[menuItems.length-1].item.push("product2Item4")

var prodItems = [
{
"product": "prod1",
"item": ["prod1Item1", "prod2Item2"]
},
{
"product": "prod2",
"item": ["prod2Item1", "prod2Item2", "prod2Item3", "prod2Item4"]
}
];
alert(prodItems[0].product);
for(var i = 0; i < prodItems.length; i++) {
alert(prodItems[i].product);
}

I see your question has been answered, but I want to suggest a small improvement to keep your code more DRY (Do not Repeat Yourself). You can use a simple function that will save you some extra typing when adding new objects.
var prodItems=[];
function addProduct(productName, items){
var product={
product: productName,
items: items
};
prodItems.push(product);
};
//sample use
addProduct("prod2",["prod2Item3", "prod2Item1", "prod2Item2", "prod2Item4"])
This will definitely also become more flexible if you need to change the object structure at some later point.

Related

Functions Invoking other Functions exercise I'm stumped on

First-time poster here and have run into a speed bump in my pre-work for a 6-month full-stack boot camp I'm enrolled in for November.
I'm working on some exercises on repl.it and this one is on javascript functions. You're told to write 3 functions called mealMaker, slice, and cook.
You're given an empty array and are told to fill it with objects like so:
const arrayOfFoodObjects = [
{
"food": "beef",
"type": "meat"
},
{
"food": "zucchini",
"type": "vegetable"
},
{
"food": "bacon",
"type": "meat"
},
{
"food": "okra",
"type": "vegetable"
}
];
They want you to have the cook function take all the objects that have "type": "meat" and return a string that says "Cooked ("food": value)" (e.g. "Cooked beef") and similarly with the slice function for "type": "vegetable" they want "("food": value) slices" (e.g. "Okra slices").
Then the mealMaker function takes what those functions spit out and creates an array as such: ["Cooked beef", "Okra slices" ...].
Where I'm stuck is I wrote a .filter() function that just returns a filtered array of those objects which I soon realized wouldn't serve its purpose. I guess I'm trying to figure out how to write a function so I can filter the meat and vegetables separately and then have them spit out the required string.
What's confusing me is how to target the "food" value and plug it into a certain string after filtering with the "type" value.
This is the rest of the code I have written so far which may or may not help.
var redMeat = arrayOfFoodObjects.filter(function(cook) {
return cook.type == "meat";
});
var veggies = arrayOfFoodObjects.filter(function(slice) {
return slice.type == "vegetable";
});
console.log(veggies, redMeat)
With the console just looking like:
[ { food: 'zucchini', type: 'vegetable' },
{ food: 'okra', type: 'vegetable' } ] [ { food: 'beef', type: 'meat' },
{ food: 'bacon', type: 'meat' } ]
I'm probably not tackling this the right way as I've spent a good amount of time trying different things I had found on Google and applying them as best I could but this was the closest I managed to get. Any help is greatly appreciated, thanks.
PS I'm not super familiar with this format of a function as I came up with this through some searches on Google. If someone wouldn't mind explaining how this may differ from the function format I'm used to seeing, that'd be awesome. I'm not sure about which part of it is the "name" of the function. The functions I've worked with so far typically look like:
function nameOfFunction(value(s)) {
*action*;
}
You are not doing what they ask.
They want a cook function and a slice function:
function cook(arr){
//for each element of the array, return its mapped value (they ask a string)
return arr.map( function(foodObject){
return `Cooked ${foodObject.food}`
})
}
function slice(arr){
//do it
}
let cooks = cook(arrayOfFoodObjects)
let slices = slice(arrayOfFoodObjects)
then feed what the function spit out to mealMaker (as instructed):
function mealMaker(cooks, slices){
return cooks.map( function(cook, idxCook){
let slice = slices[idxCook];
//guess what to do with cook and slice
})
}
mealMaker(cooks, slices)
I think something alone these lines is requested:
const cook = product => "cooked " + product.food;
const slice = product => product.food + " slices";
const mealMaker = (products) => {
const meatProducts = products.filter(product => product.type === "meat");
const veggieProducts = products.filter(product => product.type === "vegetable");
return [
...cook(meatProducts),
...slice(veggieProducts)
];
}
mealMaker(arrayOfFoodObjects);
Notice the fat arrow syntax for writing functions. How it is different compared to regular functions, is explained here on Mozilla.
Welcome holdenprkr!
I think you are on the right track! For now, we have a way to get an array of veggies and another one for meats:
var redMeat = arrayOfFoodObjects.filter(function(cook) {
return cook.type == "meat";
});
var veggies = arrayOfFoodObjects.filter(function(slice) {
return slice.type == "vegetable";
});
So far so good, now we want a cook function that takes our readMeat array, and converts it to a array of strings. So, something in the lines of:
function cook(readMeatsArray) {
// convert readMeatsArray to cookedMeatsArray
// [{'food': 'beef', 'type': 'meat'}, ...]
// to
// ['Cooked beef', ...]
}
And then a slice function for the veggies:
function slice(veggiesArray) {
// convert veggiesArray to slicedVeggiesArray
// [{'food': 'okra', 'type': 'vegetable'}, ...]
// to
// ['Okra slices', ...]
}
So, if we combine this in an mealMaker function we now have:
function mealMaker() {
// First we get our arrays
var redMeat = arrayOfFoodObjects.filter(function(cook) {
return cook.type == "meat";
});
var veggies = arrayOfFoodObjects.filter(function(slice) {
return slice.type == "vegetable";
});
// Then we convert our object arrays to string arrays
var cookedMeats = cook(redMeat);
var slicedVeggies = slice(veggies);
// Now we combine the resulting arrays and return it
var mealArray = cookedMeats.concat(slicedVeggies);
return mealArray;
}
This would be one approach, hope it helps.
PD: I left the functions cook and slice empty on purpose, you can get some inspiration from user753642's answer ;)

how to increase custom count in jquery json

If laptop model and serial id are same, i've to add new field totalModel and increase count. For example in below case: serialid "1" and laptop model "xyz" are coming two time so i want to add "totalModel" count as 2 and so on. How can i achieve this in jquery
This question is not really about jQuery, it is about mapping and filtering arrays and objects. However, we can use some jQuery convenience methods to solve it.
A large part of solving these problems is by properly defining what you want to do. It sounds from your question that you want to get a map of unique serial ids per laptop model type. We can use JavaScript's Array.prototype.reduce to produce just such a map (Note that we will take the 'sold' value for the first of each laptop model we encounter):
var laptop_models = data.reduce(function (memo, obj) {
if (!memo[obj.laptopModel]) {
memo[obj.laptopModel] = {
unique_serial_ids: [],
sold: obj.sold
};
}
if ($.inArray(obj.serialid, memo[obj.laptopModel].unique_serial_ids) === -1) {
memo[obj.laptopModel].unique_serial_ids.push(obj.serialid);
}
return memo;
}, {});
Next, we can map our laptop_models object into the array you specified as your expected result:
var result = $.map(laptop_models, function (laptop_model, model_name) {
return {
laptopModel: model_name,
totalModel: laptop_model.unique_serial_ids.length,
sold: laptop_model.sold
};
});
You got the idea already. Iterate through the array.
if them item is in a hash, increment the count, otherwise, add to the hash and set the count to 1
var hash = {};
for (var i = 0;i<data.length;i++) {
if (hash[data[i].laptopModel) {
hash[data[i].laptopModel]++;
}
else
hash[data[i].laptopModel] = 1;
}
var data = [
{
"serialid": 1,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 5
},
{
"serialid" :1,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 4
},
{
"serialid": 1,
"laptopModel": "abc",
"sold": "yes",
"cnt": 3
},
{
"serialid": 3,
"laptopModel": "xyz",
"sold": "yes",
"cnt": 2
}];
var result = []; //work if result = {};
var tempArray = []; // used to store unique name to prevent complex loop
data.forEach(function(item){
if($.inArray(item.laptopModel, tempArray)< 0){// unique name
result.push(formatData(item));
tempArray.push(item.laptopModel);
}
else{
var indexNew = $.inArray(item.laptopModel, tempArray);
result[indexNew]["totalModel"] += 1;
}
});
function formatData(item){
return{
"laptopModel": item.laptopModel,
"sold": item.sold,
"totalModel": 1
}
}
alert(JSON.stringify(result)); //expect array 2 item but it's empty array
console.log(result); //Will have result 2 item when I view console window
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

js each loop add one more depth to an object or array

I have this array of pages urls, now i need to make a hierarchy of out it.
So from this:
allPages = [
{ "url": "/polygon/color/red.html", "name": "Red" },
{ "url": "/polygon/color/blue.html", "name": "Blue" },
{ "url": "/polygon/shape/tri.html", "name": "Triangle" },
{ "url": "/weight/heavy.html", "name": "Heavy Item" }
];
To this:
siteMap = [
polygon:
color:
[{url:"red.html", name:"Red"}],
[{url:"blue.html", name:"Blue"}],
shape:
[{url:"tri.html", name:"Triangle"}],
weight:
[{url:"heavy.html", name:"Heavy Item"}],
];
The final structure can be object or array. But i can only use JS, not jQuery nor php.
EDIT: Changed Input data into array of objects. Sorry for making this harder.
Fiddle: https://jsfiddle.net/ss92kw4a/2/
several steps:
First we split the strings into arrays:
for(i in all){
all[i] = all[i].substring(1).split("/");
}
Next we do a recursive insertion:
function insert(o, a){
if(a.length == 0){return; }
if(!o[a[0]]){
o[a[0]] = {};
}
insert(o[a[0]], a.slice(1));
}
We start the recursion like this:
ans = {};
all.forEach(function(entry){
insert(ans, entry);
});
All done. The result tree is now in the ans object:
console.log(ans);
UPDATE: this code makes the last level an array: https://jsfiddle.net/ss92kw4a/3/
You may use something like this:
var allPages = [
"/polygon/color/red.html",
"/polygon/color/green.html",
"/polygon/color/blue.html",
"/polygon/shape/tri.html",
"/polygon/shape/rect.html",
"/weight/heavy.html",
"/weight/light.html"
];
var siteMap = {};
for (var i in allPages) {
var fragments = allPages[i].match(/[^\/]+/g);
if (!!fragments) {
var currentMember = siteMap;
for (var j in fragments) {
fragment = fragments[j];
if(!currentMember.hasOwnProperty(fragment)) {
currentMember[fragment] = {};
}
currentMember = currentMember[fragment];
}
}
}
Might be enhanced, notably in the fact that ending leaves are objects,
but it works.

Loop Through JSON, Insert Key/Value Between Objects?

UPDATE - Thanks for all the great answers and incredibly fast response. I've learned a great deal from the suggested solutions. I ultimately chose the answer I did because the outcome was exactly as I asked, and I was able to get it working in my application with minimal effort - including the search function. This site is an invaluable resource for developers.
Probably a simple task, but I can't seem to get this working nor find anything on Google. I am a Javascript novice and complex JSON confuses the hell out of me. What I am trying to do is make a PhoneGap Application (Phone Directory) for our company. I'll try to explain my reasoning and illustrate my attempts below.
I have JSON data of all of our employees in the following format:
[
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer"
},
{
"id":"2",
"firstname":"Mark",
"lastname":"Banana",
"jobtitle":"Artist"
},
... and so on
]
The mobile framework (Framework 7) that I am using offers a "Virtual List" solution which I need to take advantage of as our directory is fairly large. The virtual list requires you to know the exact height of each list item, however, you can use a function to set a dynamic height.
What I am trying to do is create "headers" for the alphabetical listing based on their last name. The JSON data would have to be restructured as such:
[
{
"title":"A"
},
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer"
},
{
"title":"B"
},
{
"id":"2",
"firstname":"Mark",
"lastname":"Banana",
"jobtitle":"Artist"
},
... and so on
]
I've been able to add key/value pairs to existing objects in the data using a for loop:
var letter, newLetter;
for(var i = 0; i < data.length; i++) {
newLetter = data[i].lastname.charAt(0);
if(letter != newLetter) {
letter = newLetter
data[i].title = letter;
}
}
This solution changes the JSON, thus outputting a title bar that is connected to the list item (the virtual list only accepts ONE <li></li> so the header bar is a div inside that bar):
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer",
"title":"A"
},
{
"id":"1",
"firstname":"Mike",
"lastname":"Apricot",
"jobtitle":"Engineer",
"title":""
}
This solution worked until I tried implementing a search function to the listing. When I search, it works as expected but looks broken as the header titles ("A", "B", etc...) are connected to the list items that start the particular alphabetical section. For this reason, I need to be able to separate the titles from the existing elements and use them for the dynamic height / exclude from search results.
The question: How can I do a for loop that inserts [prepends] a NEW object (title:letter) at the start of a new letter grouping? If there is a better way, please enlighten me. As I mentioned, I am a JS novice and I'd love to become more efficient programming web applications.
var items = [
{ "lastname":"Apple" },
{ "lastname":"Banana" },
{ "lastname":"Box" },
{ "lastname":"Bump" },
{ "lastname":"Can" },
{ "lastname":"Switch" }
];
var lastC = null; //holds current title
var updated = []; //where the updated array will live
for( var i=0;i<items.length;i++) {
var val = items[i]; //get current item
var firstLetter = val.lastname.substr(0,1); //grab first letter
if (firstLetter!==lastC) { //if current title does not match first letter than add new title
updated.push({title:firstLetter}); //push title
lastC = firstLetter; //update heading
}
updated.push(val); //push current index
}
console.log(updated);
Well right now you have an array of objects - prefixing the title as its own object may be a bit confusing - a better structure may be:
[
{
title: "A",
contacts: [
{
"id":"1",
"firstname":"John",
"lastname":"Apple",
"jobtitle":"Engineer",
"title":"A"
}
]
Given your current structure, you could loop and push:
var nameIndexMap = {};
var newContactStructure = [];
for (var i = 0; i < data.length; i++) {
var letter = data[i].lastname.charAt(0);
if (nameIndexMap.hasOwnProperty(letter)) {
//push to existing
newContactStructure[nameIndexMap[letter]].contacts.push(data[i])
} else {
//Create new
nameIndexMap[letter] = newContactStructure.length;
newContactStructure.push({
title: letter,
contacts: [
data[i]
]
});
}
}
newContactStructure will now contain your sorted data.
Demo: http://jsfiddle.net/7s50k104/
Simple for loop with Array.prototype.splice will do the trick:
for (var i = 0; i < data.length; i++) {
if (i == 0 || data[i-1].lastname[0] !== data[i].lastname[0]) {
data.splice(i, 0, {title: data[i].lastname[0]});
i++;
}
}
Demo. Check the demo below.
var data = [
{"lastname":"Apple"},
{"lastname":"Banana"},
{"lastname":"Bob"},
{"lastname":"Car"},
{"lastname":"Christ"},
{"lastname":"Dart"},
{"lastname":"Dog"}
];
for (var i = 0; i < data.length; i++) {
if (i == 0 || data[i-1].lastname[0] !== data[i].lastname[0]) {
data.splice(i, 0, {title: data[i].lastname[0]});
i++;
}
}
alert(JSON.stringify( data, null, 4 ));

How to get count of elements according to the value contained in javascript

I have a json array contains many elements. A part of the array is given:
var some_array = {
"0":{
"picture":"qwerty.jpg",
"textofPicture":"comment for Picture 5",
"picNo":1,
"id":25,
"uid0":125,
"uid1":123,
"uid2":126,
"uid3":127,
"uid4":124,
"u0":"149",
"u1":"80",
"u2":"71",
"u3":"108",
"u4":"158",
"accepted":false,
"su":"",
"point":0
},
"1":{
"picture":"qwerty.jpg",
"textofPicture":"comment for Picture 3",
"picNo":2,
"id":23,
"uid0":113,
"uid1":117,
"uid2":116,
"uid3":114,
"uid4":115,
"u0":"62",
"u1":"58",
"u2":"115",
"u3":"138",
"u4":"106",
"accepted":false,
"su":"",
"point":0
}
}
I want to count how many accepted key's value is true. I am sure there is good way to do this. I do not want to dive into loops.
One way to obtain the count you're looking for is like this
var count = 0;
var some_array = [
0 : {
accepted : false
},
1 : {
accepted : true
}
];
for (var i in some_array) {
if (some_array[i].accepted === true) {
count++;
}
}
return count;
Let me know if this helps and makes since to you. if need be i can make plunker for a visual.

Categories

Resources