Push Arrays' indexes into one object - javascript

How to push array indexes into one object where the correspondence between {key:value} in my example would be {authors[i]: quotes[i]}?
Please check my codepen:
http://codepen.io/anon/pen/Ndezeo
Thanks.

You could iterate authors and take the name as key and assign the item of quotes as property of the object.
var quotes = [],
authors = [],
object = {};
quotes[0] = "I have a new philosophy. I'm only going to dread one day at a time.";
authors[0] = "Charles Schulz";
quotes[1] = "Reality is the leading cause of stress for those in touch with it.";
authors[1] = "Jack Wagner";
quotes[2] = "Few things are harder to put up with than the annoyance of a good example.";
authors[2] = "Mark Twain";
quotes[3] = "The pure and simple truth is rarely pure and never simple.";
authors[3] = "Oscar Wilde";
quotes[4] = "There's no business like show business, but there are several businesses like accounting.";
authors[4] = "David Letterman";
quotes[5] = "Man invented language to satisfy his deep need to complain.";
authors[5] = "Lily Tomlin";
authors.forEach(function (k, i) {
object[k] = quotes[i];
});
console.log(object);

The answer to your question would be:
var combined = [];
for (var i = 0; i < quotes.length; i++) {
combined[authors[i]] = quotes[i]
}
console.log(combined);
But the really simple and elegant solution here would be to place all your values in a single array from the start:
var quotes = [
{
author: "Charles Schulz",
quote: "I have a new philosophy. I'm only going to dread one day at a time."
},
{
author: "Jack Wagner",
quote: "Reality is the leading cause of stress for those in touch with it."
}
/* etc... */
];
Than you can go over your quotes array with a simple for:
console.log(quotes);
for (var i = 0; i < quotes.length; i++) {
/* access each object like this:
quotes[i].author;
quotes[i].quote;
*/
}
Alternatively, depending on your needs you could structure your data in an object, with this structure:
quotes = {
"Charles Schulz":"I have a new philosophy. I'm only going to dread one day at a time.",
"Jack Wagner":"Reality is the leading cause of stress for those in touch with it."
/* etc... */
}

You can use the for...of loop and ES6 destructing or Array#reduce to build a new object.
let quotes = [];
let authors = [];
let object = {};
quotes[0] = "I have a new philosophy. I'm only going to dread one day at a time.";
authors[0] = "Charles Schulz";
quotes[1] = "Reality is the leading cause of stress for those in touch with it.";
authors[1] = "Jack Wagner";
quotes[2] = "Few things are harder to put up with than the annoyance of a good example.";
authors[2] = "Mark Twain";
quotes[3] = "The pure and simple truth is rarely pure and never simple.";
authors[3] = "Oscar Wilde";
quotes[4] = "There's no business like show business, but there are several businesses like accounting.";
authors[4] = "David Letterman";
quotes[5] = "Man invented language to satisfy his deep need to complain.";
authors[5] = "Lily Tomlin";
// for...of loop taking advantage of the new array method entries & using destructuring
for (const [index, element] of authors.entries()) {
if (!object[element])
object[element] = quotes[index];
}
console.log('Result of using for...of loop:', object);
// array method reduce: Setting an object as the initial value
const usingReduce = authors.reduce((obj, author, index) => {
if (!obj[author])
obj[author] = quotes[index];
return obj; // always return initial value
}, {}); // here I set an obj as the initial value
console.log('Result of using Array#reduce: ', usingReduce);
// using map to return an object containing the authors
// { author: author } same key/value pairs can be shortened to -> { author }
const usingMap = authors.map((author, index, authorsArray) => ({
author,
quote: quotes[index]
}));
console.log('Result of using Array#map method: ', usingMap);

Related

Grouping different arrays based on it's key

I have arrays like this,
0: {"pure_id":"1","branch_id":"45"}
1: {"pure_id":"2","branch_id":"45"}
2: {"pure_id":"3","branch_id":"45"}
3: {"pure_id":"3","branch_id":"45"}
I am looking to group the above arrays into a single array based on pure_id, so the result array will be this below, and the index will be pure_id index
1: [{"pure_id":"1","branch_id":"45"}]
2: [{"pure_id":"2","branch_id":"45"}]
3: [{"pure_id":"3","branch_id":"45"},{"pure_id":"3","branch_id":"45"}]
I am trying lots of things honestly, but I cannot make it work.
Please help.
const result = [];
for(const el of array)
(result[el.pure_id] || (result[el.pure_id] = [])).push(el);
Using the new object literal rest and spread syntax, the property expression syntax, and .reduce() makes this pretty short and simple.
var arr = [
{"pure_id":"1","branch_id":"45"},
{"pure_id":"2","branch_id":"45"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"45"}
];
var result = arr.reduce((res, {pure_id, ...props}) =>
({...res, [pure_id]: (res[pure_id] || []).concat({pure_id, ...props})})
, {});
console.log(result);
The .reduce() is of course just creating a new object. Each iteration takes the accumulated properties and adds them to an object literal, but with the pure_id being the concatenation of the properties of the current object (copy) to an array.
I often see people struggle with something in programming that outside of it would not be a problem. Instead of arrays and objects, you can think of it as fruit.
Imagine a bucket of fruit. You want to sort the one bucket of fruit into 1 bucket for each color of fruit (color just being a property of a piece of fruit). So you would:
grab one fruit at a time
figure out it's color
if there is no bucket for that color, get one
put the fruit in the proper bucket
repeat until there are no fruits left
What we created was an algorithm for sorting fruit by color. The problem you are solving is very similar. In pseudocode it would be:
for each fruit
color = fruit.color
if not bucket[color]
make bucket[color]
put fruit in bucket[color]
to translate that to JS
var fruits = [
{color: "red"},
{color: "orange"},
{color: "pink"},
{color: "red"}
];
var buckets = {};
for (var i=0; i<fruits.length; i++) {
var fruit = fruits[i];
var color = fruit.color;
if (!buckets[color])
buckets[color] = [];
buckets[color].push(fruit);
}
So now, if you want to work with your array, the algorithm stays the same you just swap out the parts.
var things = [
{"pure_id":"1","branch_id":"45"},
{"pure_id":"2","branch_id":"45"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"45"}
];
var grouped = [];
for (let i=0; i<things.length; i++) {
var thing = things[i];
var id = thing['pure_id'];
if (!grouped[id])
grouped[id] = [];
grouped[id].push(thing);
}
console.log(grouped)
So, here we are at the first solution. It works! There are better solutions (using reduce, forEach or others) but don't let data structures like arrays or dictionaries scare you away. Think about it in simpler terms if it helps.
If don't use reduce, the codes will be like below:
Assuming your expected result is one array like:
[[{'pure_id':0, 'branch_id':1}], [{'pure_id':1, 'branch_id':2}]]
//assuming your array is like below:
var test = [{"pure_id":"1","branch_id":"43"},
{"pure_id":"2","branch_id":"44"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"46"}]
var result = []
var index_db = {} //use dict to save the mapping between the index of result and pure_id
var index = 0
test.forEach(function(item){
if(item.pure_id in index_db){
result[index_db[item.pure_id]].push(item)
}
else{
result.push([item])
index_db[item.pure_id] = index++
}
});
console.log(result)
Below is one reduce version:
//assuming your array is like below:
var test = [{"pure_id":"1","branch_id":"43"},
{"pure_id":"2","branch_id":"44"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"46"}]
result = test.reduce(function(pre, cur){
if(cur['pure_id'] in pre['indexes']){
pre['result'][pre['indexes'][cur['pure_id']]].push(cur)
}
else{
pre['result'].push([cur])
pre['indexes'][cur['pure_id']] = pre['pos']++
}
return pre
}, {'pos':0, 'indexes':{}, 'result':[]})
console.log(result['result'])

Search through json with keywords

I need some help with a small thing I am struggeling with. I have to create a general search input that searches though a json of music numbers. The user has to be able to type an album/track or artist in the searchbar and then he'll get the result. Like any other search bar does. Only this one searches based on keypresses instead of a submit button.
The part where I'm stuck is that I've received a large JSON file with more than 5000 entries. And my search bar has to be able to identify entries based on partially typed "keywords". So for instance if I want to search for madonna and I type in "mado" I should already get some madonna in my results ( of course its possible to get other entries that have mado in their title or someting! ).
Sorry for my lack of good grammar but I try my best to explain the situation as good as possible!
Now for the question! The thing I'm struggeling with is how I loop through a json file to search for these keywords. This is a small portion of the json I receive:
{
"1": {
"track": "Dani California",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"2": {
"track": "Tell me baby",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"3": {
"track": "Snow (Hey Oh)",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
}}
Normally I would create a function that is something like this:
for(var i = 0; i < data.length; i++){
if(data[i].album == 'red hot'){
console.log(data[i].album)
}}
But in this case I want to loop through the json, looking for enties that contain the search value an save it to an object for later usage
Is it possible to do this all at once? So to check the artist/title/album at once, or would it be better to create a small filter?
If something is not clear about my explanation please met me know I tried my best to be as clear as I could be!
I dont think searching 5000 entries should cause performance issues.
Check out this code which should return the desired entries when you call search('text')
var data = JSON.parse('JSON DATA HERE') // dataset
var search_fields = ['track','artist','album'] //key fields to search for in dataset
function search(keyword){
if(keyword.length<1) // skip if input is empty
return
var results = []
for(var i in data){ // iterate through dataset
for(var u=0;u<search_fields.length;u++){ // iterate through each key in dataset
var rel = getRelevance(data[i][search_fields[u]],keyword) // check if there are matches
if(rel==0) // no matches...
continue // ...skip
results.push({relevance:rel,entry:data[i]}) // matches found, add to results and store relevance
}
}
results.sort(compareRelevance) // sort by relevance
for(i=0;i<results.length;i++){
results[i] = results[i].entry // remove relevance since it is no longer needed
}
return results
}
function getRelevance(value,keyword){
value = value.toLowerCase() // lowercase to make search not case sensitive
keyword = keyword.toLowerCase()
var index = value.indexOf(keyword) // index of the keyword
var word_index = value.indexOf(' '+keyword) // index of the keyword if it is not on the first index, but a word
if(index==0) // value starts with keyword (eg. for 'Dani California' -> searched 'Dan')
return 3 // highest relevance
else if(word_index!=-1) // value doesnt start with keyword, but has the same word somewhere else (eg. 'Dani California' -> searched 'Cali')
return 2 // medium relevance
else if(index!=-1) // value contains keyword somewhere (eg. 'Dani California' -> searched 'forn')
return 1 // low relevance
else
return 0 // no matches, no relevance
}
function compareRelevance(a, b) {
return b.relevance - a.relevance
}
Since it's not an array you can't use Array.prototype.filter() unless you turn your object into an array. You could do this every time you get a new Json, no need to do this with every search.
var myArray = [];
for(var elementName in data) //We iterate over the Object to get the names of the nested objects
myArray.push(data[elementName]); //We get the objects of the json and push them inside our array.
Then you can use .filter to filter your data, I recommend using regex:
var userQuery = 'Mado' //user input
var myRegex = new RegExp('.*' + userQuery + '.*','gi'); //We create a new regular expression, this one tests if the text is contained within a string.
var filteredArray = myArray.filter(function(item){
//We test each element of the object to see if one string matches the regexp.
return (myRegex.test(item.track) || myRegex.test(item.artist) || myRegex.test(item.album))
});
filteredArray should be the elements of the json you need.
Array.prototype.filter MDN
RegeExp MDN
Here's a pattern I often use for filter functionalities. Some key points are:
Always build an index property that contains the appended string of the filterable values. For example, if the values of 'track','artist' and 'album' can be filtered on, then join their values into a string, and add that string as one of the properties to the original object.
This helps quickly search using indexOf, rather than having to iterate through each object when filtering. It significantly improves the performance as those iterations and additional number of properties*number of objects comparisons are no longer required. In your case, you'd be saving roughly 10k comparisons and 15k iterations with every filter operation.
If the filter operation is case-insensitive, use toLowerCase while appending the values to build indexes. It also saves you from performing those many toLowerCase operations every time filter is called.
Always create an array of objects, rather than an object with object properties. I don't have specific stats on whether this improves performance or not, but it provides you some array methods such as array.filter or array.sort that you could utilize to improve UX. I haven't done that in the snippet, but you can do that quite easily while preparing the data.
var data = {
"1": {
"track": "Dani California",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"2": {
"track": "Tell me baby",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"3": {
"track": "Snow (Hey Oh)",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
}};
// One time activity!
// Build search indexes, for every object.
for(var prop in data) {
if(data.hasOwnProperty(prop)) {
var index = "";
var item = data[prop];
// Iterate over each object and build the index by appending the values of each property.
for(var attr in item) {
if(item.hasOwnProperty(attr)) {
// Note: Different values are separated by a hash as hash # is unlikely to come into the search query.
index = index + item[attr] + "#";
}
}
// Insert the index property into the object.
// Also notice the toLowerCase that allows for case insenstive searches later on.
item.index = index.toLowerCase();
}
}
console.log("Prepared data:" ,data);
// Filter process.
var key = "Sn";
var keyLowerCase = key.toLowerCase();
// Iterate over the objects and compare the index prpoerty to match with the search string.
var filteredData = [];
for(var prop in data) {
if(data.hasOwnProperty(prop)) {
var item = data[prop];
if(item.index.indexOf(keyLowerCase) >= 0 ){
filteredData.push(item);
}
}
}
console.log("Filtered data:", filteredData);

Create an associative array after .split ()

I take the example from the developer.mozilla.org official documentation so you can answer it more easily:
var names = "Harry Trump; Fred Barney; Helen Rigby; Bill Abel; Chris Hand";
var re = / \ s *; \ s * /;
var nameList = names.split (re);
This regular expression produces an array formed by the various elements divided by the character ;.
My problem is this: I would like to associate with the array that is out of the element from which it was extracted, that is, ;.
Basically the goal is to get something like this:
[
{
";": ["Harry Trump"]
},
{
";": ["Fred Barney"]
}
...
]
instead of
[ "Harry Trump", "Fred Barney" , ... ]
Would you like to tie them up?
Here you go with the solution https://jsfiddle.net/fq3238ku/1/
var names = "Harry Trump, Fred Barney, Helen Rigby, Bill Abel, Chris Hand";
var splitName = names.split(',');
var data = [];
for(var i in splitName){
data[i] = {";" : [splitName[i]]};
}
console.log(data);
If your separator is variable you can do this way
let names = "Harry Trump, Fred Barney, Helen Rigby, Bill Abel, Chris Hand"
let re = /\s*(,)\s*/
let res = names.split(re).map(
(currentValue, index, array) => {
if (index%2!=0) {
return {
[currentValue]: (array[index-1] )
}
}
}
)
.filter((n)=>n)
console.log(res)
What you want to achieve is simply not possible. Once you have a value under key ; then assigning another value will simply overwrite the previous one.

Split an object into array of objects based on a condition in JavaScript

How to split an object into array of objects based on a condition.
oldObject = {"Chicago, IL:Myrtle Beach, SC": 0.005340186908091907,
"Portsmouth, NH:Rock Hill, SC": 0.0063224791225441205,
"Columbia, SC:Laconia, NH": 0.006360767389277389,
"Council Bluffs, IA:Derry, NH": 0.0016636141225441225}
Above is the given sample object. I want to make an array of objects like this,
newArray = [{"city":"Chicago", "similarTo":"Myrtle"},
{"city":"Portsmouth", "similarTo":"Rock Hill"},
{"city":"Columbia", "similarTo":"Laconia"},
{"city":"Council Bluffs", "similarTo":"Derry"}]
I have been scratching my head with this for a while now. How can I get the above array(newArray)?
Here is a bunch of code you can try.
1) Iterate over oldObject and get the name of the property.
2) Split that name into an array based on the ":" character, since it separates the cities
3) Go over that new array, splitting it on the "," character (so as not to get the states).
4) Put the values into the newObject, based on whether it's the first or second part of the original property name.
5) Push that newObject, now with items, into a newArray.
Basically, this parses apart the name and does some array splitting to get at the right values. Hope it helps and helps you understand too.
var oldObject = {"Chicago, IL:Myrtle Beach, SC": 0.005340186908091907,
"Portsmouth, NH:Rock Hill, SC": 0.0063224791225441205,
"Columbia, SC:Laconia, NH": 0.006360767389277389,
"Council Bluffs, IA:Derry, NH": 0.0016636141225441225};
var newArray = [];
for (object in oldObject) {
var thisObjectName = object;
var thisObjectAsArray = thisObjectName.split(':');
var newObject = {
'city': '',
'similar_to': ''
};
thisObjectAsArray.forEach(function(element,index,array) {
var thisObjectNameAsArray = element.split(',');
var thisObjectNameCity = thisObjectNameAsArray[0];
if(index===0) {
newObject.city = thisObjectNameCity;
} else if(index===1) {
newObject.similar_to = thisObjectNameCity;
}
});
newArray.push(newObject);
}
console.log(newArray);
PS: to test, run the above code and check your Developer Tools console to see the new array output.

Filter JSON with unique key/values

I have a JSON object structured as such:
var theSchools = {
Bradley University: "bru",
Knox College: "knox",
Southern Illinois University Edwardsville: "siue",…
}
What I am trying to achieve is a way of retrieving the key, in this case the school name, by supplying the value, the schools 'code.'
It does not appear that I will be able to have this restructured correctly, i.e.
var theSchools = [
{
schoolName:"Bradley University",
schoolCode: "bru"
}
{
schoolName: "Knox College",
schoolCode: "knox"
}
]
so I'm kind of stuck with what I got.
I know the following code is incorrect, but it's essentially what I want to achieve:
if(getParameterByName("schoolId").length>0){
var schoolid = getParameterByName("schoolId");
var schoolName= theSchools.schoolid;
jQuery("h1").after("<h2>Welcome to <strong>"+schoolName+"</strong></h2>")
}
You can use a for...in loop to loop over each property in the object, and return the property name if the value matches:
var theSchools = {
"Bradley University": "bru",
"Knox College": "knox",
"Southern Illinois University Edwardsville": "siue"
};
function findSchool(code) {
for (var s in theSchools) {
if (theSchools[s] === code)
return s;
}
return null;
}
document.getElementById('school').innerText = findSchool('knox');
<div id="school"></div>
The question is if you really need it this way (see answer #James), here's what you requested:
var theSchools = {
"Bradley University": "bru",
"Knox College": "knox",
"Southern Illinois University Edwardsville": "siue"
}, schoolMap = {};
for (var schoolName in theSchools) {
var code = theSchools[ schoolName ];
schoolMap[ code ] = schoolName;
}
document.body.innerHTML = schoolMap["bru"]; // Bradley University
You don't have to use a for loop to check if property exists. Use hasOwnProperty method.
if (theSchools.hasOwnProperty("Knox College")) {
//do stuff
}
Working example: https://jsfiddle.net/7q9czdpc/

Categories