trying to create an array of objects given 2 arrays + map - javascript

I have the following 2 arrays here:
> chNameArr
[ 'chanel1',
'chanel2',
'chanel3',
'chanel4',
'chanel5',
'chanel6',
'chanel7' ]
and here:
> a
[ 'channelName'
'status',
'connections',
'socketIds',
'lastRun',
'numberOfRuns',
'timeout' ]
what I am trying to achieve is the following objects per channel in an array where channelName from a get the value from chNameArr but the rest of 'a' gets an empty string
file=[{"channelName":"chanel1","status":"", "connections":"", "socketIds":"", "lastRun":"", "numberOfRuns":"", "timeout":""},
.
.
.
{"channelName":"chanel7","status":"", "connections":"", "socketIds":"", "lastRun":"", "numberOfRuns":"", "timeout":""}]
this is my attempt
> chNameArr.map(function(d){return {channelName:d}})
[ { channelName: 'chanel1' },
{ channelName: 'chanel2' },
{ channelName: 'chanel3' },
{ channelName: 'chanel4' },
{ channelName: 'chanel5' },
{ channelName: 'chanel6' },
{ channelName: 'chanel7' } ]

chNameArr.map(function(d) {
result = {};
result[a[0]] = d;
for (var i=1; i<a.length; i++) {
result[a[i]] = "";
}
return result;
})
There is no one-liner to solve this problem in general, although if you don't actually need to use the array a you could manually construct {channelName:d, status: "", ...} in your original map.

Related

Save last elements from deep nested object to a non global array

I already found out, how to get the last elements of a deep nested object.
See here for working example: How to get the last children in a deeply nested array with objects
Now I dont want to log the names like in the example with console.log(subObj.name), instead I want to save them in an array, which shouldnt be global. I just want a function return this array.
Is this somehow possible without declaring a global array for this ?
This is my code:
function childrenNames (obj) {
var lastChildren = [];
obj.forEach((subObj) => {
if (subObj.hasOwnProperty('specification') && subObj.specification instanceof Array && subObj.specification.length > 0) {
childrenNames(subObj.specification);
} else {
if (subObj.hasOwnProperty('name')) {
lastChildren.push(subObj.name)
}
}
})
console.log(lastChildren);
return lastChildren
}
But its just returning 4 different arrays instead of 1 containing all last children.
I am not sure whether this is a valid answer and I do not understand it but I am leaving it for now because it does appear, superficially at least, to answer the question. It does not require a global array to be declared as far as I can tell?
var obj = [
{
name: 'something',
children: [
{
name: 'something',
children: [
{
name: 'no child'
},
{
name: 'something empty',
children: [ ]
}
]
}
]
},
{
name: 'something',
children: [
{
name: 'something',
children: [
{
name: 'no child'
}
]
}
]
},
{
name: "children isn't an array",
children: 42
}
]
function childrenNames (obj) {
var lastChildren = [];
obj.forEach((subObj) => {
if (subObj.hasOwnProperty('specification') && subObj.specification instanceof Array && subObj.specification.length > 0) {
childrenNames(subObj.specification);
} else {
if (subObj.hasOwnProperty('name')) {
lastChildren.push(subObj.name)
}
}
})
// console.log(lastChildren);
return lastChildren
}
const res = childrenNames(obj);
console.log('res', res);

How to watch deep array using computed in Vuejs

I made a component like below in Vuejs.
But my goal is I want to get the value inside of filterdShoes of watch.
data():{
coor: [
{ "name": '',
"shoes": '' },
{ "name": '',
"shoes": '' }
]
},
computed {
filteredAny(){
return this.coor.filter(it=>['shoes','name'].includes(it));
},
filteredShoes(){
return this.coor.filter(it=>it === 'shoes');
},
filteredName(){
return this.coor.filter(it=>it === 'name');
}
}
watch {
filteredShoes(){
console.log('The shoes are changed');
}
}
So I tried like below.But it says val is undefined.
I hope that 'val' is defined as 'coor' of data.
How can I fix this code? Thank you so much for reading this.
watch {
filteredShoes(val){
for(let i=0; i < val.length; i+=1){}
}
}
Since this.coor is an array of objects, it will be an object. Thus it != 'shoes', and your filter will return an empty array.
Assuming you are using computed filteredShoes() like this:
<div v-for="shoe in filteredShoes"> ... </div>
Then you can just use the computed property, no need for the watcher. Everytime elements are added to/removed from the array, the computed prop will run. The computed property will not run if the properties of an object in the array are changed.
Also, I'm not quite sure why your this.coor has such a structure, so I'm using this:
coor: [
{ "name": 'Model 1', "shoes": 'Nike' },
{ "name": 'Model 2', "shoes": 'Reebok' }
]
...
computed {
filteredShoes(){
let shoes = this.coor.filter(item => item.shoes === 'Nike');
for(let i = 0; i < shoes.length; i++){ ... } // assuming you're modifying each object here
return shoes; // return an array to be looped in HTML
},
}
If you're trying to filter by type, I would recommend changing your coor to the following structure:
coor: [
{ "name": 'Model 1', "type": 'shoe' },
{ "name": 'Model 2', "type": 'shoe' }
]
...
computed {
filteredShoes(){
let shoes = this.coor.filter(item => item.type === 'shoe');
...
return shoes; // return an array to be looped in HTML
},
}
If you need to deep computed in array, as bellow
computed: {
computedArray: {
cache: false,
get() {
return this.sourceArray;
},
},
},

splice is not removing the first index from array of objects

I have two arrays of objects and I want to compare the objects of the first array to the ones of the second array. If they match, I use the splice to remove the object from the second array.
I have the following code
existing.forEach((existingitem, existingindex, existingfeatures) => {
(newdatafeat.features).forEach((newitem, newindex, newfeatures) => {
console.log('existing index-name --- new index-name', existingindex ,' - ',existingitem.values_.name,' - ',newindex,' - ',newitem.properties.name,'-----');
if (existingitem.values_.id == newitem.properties.id && existingitem.values_.cat == newitem.properties.cat){
console.log(' index to remove - ', newindex); (newdatafeat.features).splice(newindex,1);
}
})
});
So, If existing is
var existing= [
{ info: true, values_:{id:1, cat:true, name : "John"} },
{ info : true, values_:{id:2, cat:false, name : "Alice"} }
];
and newdatafeat.features is
var newdatafeat= {
status:scanned,
features : [ { info: true, properties:{id:1, cat:true, name : "Mike"} },
{ info : false, properties:{id:22, cat:false,name : "Jenny"} } ]
};
Then, Mike from newdatafeat.features should be removed.
The error is that every item of the newdatafeat.features array with index 0 is not removed. In the loop, I can see index to remove - 0, but Mike is never removed. I know, because if I console.log the newdatafeat.features after the loops, Mike is there
This is inside an angular6 code.
What am I missing here?
Thanks
I had to clean up some code, but it looks like yours is working fine. It identified one element to be removed, called slice and it was gone.
var existing = [{
info: true,
values_: {
id: 1,
cat: true,
name: "John"
}
},
{
info: true,
values_: {
id: 2,
cat: false,
name: "Alice"
}
}
];
var newdata = {
status: "scanned",
features: [
{
info: true,
properties: {
id: 1,
cat: true,
name: "Mike"
}
},
{
info: false,
properties: {
id: 22,
cat: false,
name: "Jenny"
}
}
]
};
existing.forEach(
(existingitem, existingindex, existingfeatures) => {
(newdata.features).forEach((newitem, newindex, newfeatures) => {
console.log('existing index-name --- new index-name', existingindex, ' - ', existingitem.values_.name, ' - ', newindex, ' - ', newitem.properties.name, '-----');
if (existingitem.values_.id == newitem.properties.id && existingitem.values_.cat == newitem.properties.cat) {
console.log(' index to remove - ', newindex);
(newdata.features).splice(newindex, 1);
}
})
});
console.log(newdata.features);
The main problem here is that you are iterating an array in a loop, but you are removing items from that array in the same loop. So the index will often be off, and the wrong element or no element will be removed. It can be hard to reproduce with simple examples, but here ya go:
function removeVowels(letters) {
letters.forEach((element, index, arr) => {
if ('aeiou'.indexOf(element) > -1) {
arr.splice(index, 1);
}
});
}
var myArray = ['a','b','c','d','e'];
removeVowels(myArray);
console.log(myArray);
// works great!
var myArray = ['a','e','c','d','b'];
removeVowels(myArray);
console.log(myArray);
// wtf!
A simple way to approach this problem is to handle the looping manually, and change the index manually if you DO remove an element.
function removeVowels(letters) {
for (var i=0; i < letters.length; i++) {
if ('aeiou'.indexOf(letters[i]) > -1) {
letters.splice(i, 1);
i--;
}
}
}
var myArray = ['a','b','c','d','e'];
removeVowels(myArray);
console.log(myArray);
// works great!
var myArray = ['a','e','c','d','b'];
removeVowels(myArray);
console.log(myArray);
// hurray!

Searching JSON deeply nested Objects with dynamic keys using Lodash?

I have a nested JSON that I'd like to search through using lodash. How can I get the root object from data if a search term I'm looking for is within certain keys, and with one of the keys being dynamic?
For example, if I have:
"data": [
{
"name": "Bob's concourse"
"activities": [
{
"day": "Monday",
"routines":
{
"Biking":
{
"details": "won 3 trophies"
"type": "road"
},
"Kayaking":
{
"details": "participated in 3 races"
"type": "rhythm"
}
}
}
}
]
},
{..other_data_etc...},
]
activities can be []; it's not guaranteed that it contains any data.
routines keys are dynamic. ie, Biking, Kayaking are dynamic strings. It can be anything.
If I want to search for an races (case insensitive), I want to search specifically in:
data.name
data.activities.routines.* (the dynamic keys)
data.activities.routines.*.details
If any one of those matches, then it will return the root object: { "name": "Bob", ..... }
I was able to get the name to return:
function searchText(collection, searchterm) {
return _.filter(collection, function(o) {
return _.includes(o.name.toLowerCase(), searchterm)
} );
};
But I'm still new to lodash, and I was unable to get any of the nested searches to return correctly, especially with the dynamic keys part.
Could anyone help explain a solution?
Expanding on your existing attempt with lodash:
const obj = {
data: [{
name: 'Bob\'s concourse',
activities: [{
day: 'Monday',
routines: {
Biking: {
details: 'won 3 trophies',
type: 'road'
},
Kayaking: {
details: 'participated in 3 races',
type: 'rhythm'
}
}
}]
}]
};
function search(str, data) {
const searchStr = str.toLowerCase();
// Only return the entries that contain a matched value
return _.filter(data, (datum) => {
// Check if name matches
return _.includes(datum.name, searchStr)
|| _.some(datum.activities, (activity) => {
return _.entries(activity.routines).some(([routine, {details}]) => {
// Check if dynamic routine matches or details
return _.includes(routine, searchStr) || _.includes(details, searchStr);
});
});
});
}
console.log(search('foobar', obj.data));
console.log(search('races', obj.data));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>
You can also accomplish this with plain JavaScript. Using some newish syntax such as destructuring assignment and newish native methods such as Object.entries essentially follows the same pattern as using lodash:
const obj = {
data: [{
name: 'Bob\'s concourse',
activities: [{
day: 'Monday',
routines: {
Biking: {
details: 'won 3 trophies',
type: 'road'
},
Kayaking: {
details: 'participated in 3 races',
type: 'rhythm'
}
}
}]
}]
};
function search(str, data) {
const regex = RegExp(str, 'i');
// Only return the entries that contain a matched value
return data.filter((datum) => {
// Check if name matches
return regex.test(datum.name)
|| datum.activities.some((activity) => {
return Object.entries(activity.routines).some(([routine, {details}]) => {
// Check if dynamic routine matches or details
return regex.test(routine) || regex.test(details);
});
});
});
}
console.log(search('foobar', obj.data));
console.log(search('races', obj.data));

Recursion in JavaScript to search in heavy JSON

I am facing an algorithmic conception problem. With JavaScript language, I have an heavy JSON object of about 11 000 lines, that is the result of the conversion of an HTML file. The structure of the JSON is similar to the one of the DOM, which means that an Object can have a property children, a data structure composed of other similar Object. The goal is to search in the JSON and extract the information of the property itemprop of the Object that has that property. The itemprop attribute is in and Object inside the attributes attribute that some of the first mentioned Object have.
Object Structure
{ type: 'x',
tagName: 'y',
attributes: { "itemprop" : "valueWanted" },
children:
[ Object, Object, Object]
}
I thought of a recursive algorithm for solution. Unfortunately, I am not familiar with recursion and the next code is not working.
Recursive Algorithm
var searchAttributesRecursive = function(children) {
for (var i = 0; i < children.length; ++i) {
if (children[i].hasOwnProperty('children')) {
return searchAttributesRecursive(children[i].children);
}
else {
if (children[i].hasOwnProperty('attributes')) {
if (children[i].attributes.itemprop === "valueWanted") {
console.log('success')
}
}
}
return; // probably a problem that breaks the loop
}
};
searchAttributesRecursive(startingChildren);
There is maybe another more effective generic algorithms to get this task done. I am open to suggestions.
Update
Thank you for all solutions and explanation provided. More particularly, have a look to #ChrisG's simple solution. Now, I would like to add a special condition in the algorithm.
If I would like to retrieve the data from the next object, outside of the scope of the children where an object has the wantedValue2, do you have an idea how I can access this data? The algorithm would have a special case where it meets wantedValue2, and don't want to extract directly the data of itemprop.
Object Structure Special Case
{
"type": "",
"tagName": "",
"attributes": {
"itemprop": "wantedValue"
},
"children": [{
"type": "",
"content": ""
}
]
},
{
"type": "",
"content": ""
}]
},
{
"type": "",
"tagName": "",
"attributes": {},
"children": [
{
"type": "",
"content": "here"
}
]
Here's a shorter version:
Note that the function expects an array, so if your object is not an array, you have to use findItemprop([dom], "wanted")
function findItemprop(data, value, found) {
if (!found) found = [];
data.forEach((node) => {
if (node.attributes && node.attributes.itemprop == value)
found.push(node);
if (node.children) findItemprop(node.children, value, found);
});
return found;
}
var dom = [{
tag: "root",
children: [{
tag: "header",
children: [{
tag: "div"
}]
}, {
tag: "div",
id: "main",
children: [{
tag: "p",
attributes: {
itemprop: "wanted"
}
}]
}, {
tag: "footer",
children: [{
tag: "span",
content: "copyright 2017",
attributes: {
itemprop: "wanted"
}
}]
}]
}];
console.log(findItemprop(dom, "wanted"));
Your return will break the loop. You just want to return if it does return:
var searchAttributesRecursive = function(children) {
for (var i = 0; i < children.length; ++i) {
if (children[i].hasOwnProperty('children')) {
var result=searchAttributesRecursive(children[i].children);
if(result) return result;//if weve found sth, return
}
if (children[i].hasOwnProperty('attributes')) {
if (children[i].attributes.itemprop === "valueWanted1") {
console.log('success')
return children[i];//return sth useful
}
}
}
return false;//nothing found in this and in all childs
};
var elem=searchAttributesRecursive(startingChildren);
This returns the first found child. You may want to return an array instead:
var searchAttributesRecursive = function(children,result=[]) {
for (var i = 0; i < children.length; ++i) {
if (children[i].hasOwnProperty('children')) {
searchAttributesRecursive(children[i].children,result);
}
if (children[i].hasOwnProperty('attributes')) {
if (children[i].attributes.itemprop === "valueWanted1") {
console.log('success')
result.push(children[i]);//return sth useful
}
}
}
return result;//return all results found
};
var arr=searchAttributesRecursive(allElems);
arr.forEach(console.log);
Through passing an array as optional parameter it is fast and easy to store the traversal of multiple trees in one result:
var arr=[];
searchAttributesRecursive(allElems,arr);
searchAttributesRecursive(allElemsTwo,arr);
Give Jonas w the credit for their answer, I'm just tagging on to help correct some of the confusion surrounding the recursion, and hopefully make the it a little easier to understand and work with.
First, you're passing in the array of children. That's fine, but then you have to access each one from its array index as you check them. My recommendation is to make your function handle only one item at a time. (I'm going to use Jonas w's method of collecting nodes, because there may be more than one node with this attribute. I'm also going to add the attribute name as a parameter to make it a little more dynamic.)
function searchAttributesRecursive(currentNode, parameterName, results=[]){
}
Now you can concentrate on one and only one node at a time. Once it has passed the check, you can move on to the children.
function searchAttributesRecursive(currentNode, parameterName, results=[]){
if(currentNode.attributes && currentNode.attributes[parameterName]){
results.push(currentNode);
}
if(currentNode.children){
for(var i = 0, len = currentNode.children.length; i < len; ++i){
searchAttributesRecursive(currentNode.children[i], parameterName, results);
}
}
}
Calling it like this:
var results = [];
searchAttributesRecursive(yourJsObject, "itemprop", results);
...populates results with nodes which contain the "itemprop" attribute. You can now print the attribute values with a simple loop:
for(var i = 0, len = results.length; i < len; ++i){
console.log(i, results[i].attributes.itemprop);
}
You can do this by using the .some() function. What this does is it will return true if any iteration returns true, otherwise it returns false. So, for every key in the current object, you will check if the property is === 'attributes', and if so, you will check the itemprop property for the desired value. If the current key is not 'attributes', and is === 'children' it will recurse and check each child object in the same way.
var searchAttributesRecursive = function(obj, valueWanted) {
if (obj instanceof Object) {
if (obj.attributes && obj.attributes.itemprop === valueWanted) {
return true;
}
if (obj.children) {
return obj.children.some(function(_obj) {
return searchAttributesRecursive(_obj, valueWanted);
});
} else {
return false;
}
} else {
return false;
}
};
var obj = {
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue0"
},
children: [{
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue1"
},
children: []
},
{
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue2"
},
children: [{
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue3"
},
children: []
}]
}
]
};
console.log("Found 'wantedValue0': " + searchAttributesRecursive(obj, "wantedValue0"));
console.log("Found 'wantedValue1': " + searchAttributesRecursive(obj, "wantedValue1"));
console.log("Found 'wantedValue2': " + searchAttributesRecursive(obj, "wantedValue2"));
console.log("Found 'wantedValue3': " + searchAttributesRecursive(obj, "wantedValue3"));
console.log("Found 'wantedValue4': " + searchAttributesRecursive(obj, "wantedValue4"));
EDIT - To make this work dynamically and search for itemprop === wantedValue in any nested property or nested child property, you can do the following:
var searchAttributesRecursive2 = function(data, valueWanted) {
if (Array.isArray(data)) {
return data.some(function(elem) {
return searchAttributesRecursive2(elem, valueWanted);
});
} else if (data instanceof Object) {
return Object.keys(data).some(function(key) {
var prop = data[key];
return prop.itemprop === valueWanted || searchAttributesRecursive2(prop, valueWanted);
});
} else {
return false;
}
};
var obj = {
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue0"
},
children: [{
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue1"
},
children: []
},
{
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue2"
},
children: [{
type: 'x',
tagName: 'y',
attributes: {
"itemprop": "wantedValue3"
},
children: []
}]
}
]
};
console.log("Found 'wantedValue0': " + searchAttributesRecursive2(obj, "wantedValue0"));
console.log("Found 'wantedValue1': " + searchAttributesRecursive2(obj, "wantedValue1"));
console.log("Found 'wantedValue2': " + searchAttributesRecursive2(obj, "wantedValue2"));
console.log("Found 'wantedValue3': " + searchAttributesRecursive2(obj, "wantedValue3"));
console.log("Found 'wantedValue4': " + searchAttributesRecursive2(obj, "wantedValue4"));

Categories