I have an object with keys and data. From a key I want to get the previous item.
I've seen similar topics before but the solutions are really complicated.
I also added a function that does not work but how I wish it would work
Simplified code
let obj = {
slug: 'my-page',
title: 'My title',
description: 'My description',
content: 'My content'
};
let previous = obj.previousItem('description'); // Does not work
console.log(previous);
Expected result
{ title: 'My title'
}
ES5 or even ES6 is fine
I prefer a simple solution to a complicated one, maybe without loops
I think somethink like this
Object.prototype.previousItem = function(propName) {
const arr = Object.keys(this);
let indx = arr.indexOf(propName)-1;
if (indx<0) return null;
const result = {};
result[arr[indx]] = this[arr[indx]];
return result;
}
Object used to be to have no order, but actually they have and I would not rely on this order.
But anyway, you could filter by the next key/value pair and get an object.
let obj = { slug: 'my-page', title: 'My title', description: 'My description', content: 'My content' },
previous = Object.fromEntries(Object
.entries(obj)
.filter((_, i, { [i + 1]: next = [] }) => next[0] === 'description')
);
console.log(previous);
Object.prototype.previousItem = function(propName) {
const arr = Object.keys(this);
let indx = arr.indexOf(propName)-1;
if (indx<0) return null;
const result = Object.create(null); // just clear output
result[arr[indx]] = this[arr[indx]];
return result;
}
let obj = {
slug: 'my-page',
title: 'My title',
description: 'My description',
content: 'My content'
};
let previous = obj.previousItem('description'); // work
console.log(previous);
You can try following to get the previous item
let object = {
slug: 'my-page',
title: 'My title',
description: 'My description',
content: 'My content'
}
let previous = previousItem(object, 'description');
console.log(previous);
function previousItem(object, str) {
let lastKey = "";
for (const key in object) {
if (object.hasOwnProperty(key)) {
if (key == str){
lastKey = lastKey || key;
let obj = { };
obj[lastKey] = object[lastKey];
return obj;
} else {
lastKey = key;
}
}
}
}
Related
Say I have the following strings:
"files/photos/foo.png"
"files/videos/movie.mov"
and I want to convert them to the following object:
{
name: "files"
children: [{
name: "photos",
children: [{
name: "foo.png",
id: "files/photos/foo.png"
}]
},{
name: "videos",
children: [{
name: "movie.mov",
id: "files/videos/movie.mov"
}]
}]
}
What would be the best approach for doing so? I've tried writing some recursive functions, however admit that I'm struggling at the moment.
Here's a quick snippet with a possible solution. It uses nested loops, the outer splitting each path by the delimeter and pop()ing the file portion out of the array. The inner iterates the parts of the path and constructs the heirarchy by reasigning branch on each iteration. Finally the file portion of the path is added to the deepest branch.
const data = [
'files/photos/foo.png',
'files/photos/bar.png',
'files/videos/movie.mov',
'docs/photos/sd.jpg'
];
const tree = { root: {} }
for (const path of data) {
const parts = path.split('/');
const file = parts.pop();
let branch = tree, partPath = '';
for (const part of parts) {
partPath += `${part}/`;
if (partPath === `${part}/`) {
tree.root[partPath] = (tree[partPath] ??= { name: part, children: [] });
} else if (tree[partPath] === undefined) {
tree[partPath] = { name: part, children: [] };
branch.children.push(tree[partPath]);
}
branch = tree[partPath];
}
branch.children.push({ name: file, id: path });
}
const result = Object.values(tree.root)
console.log(JSON.stringify(result, null, 2))
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row::after { display: none !important; }
Or as a function.
function mergeAssets(assets) {
const tree = { root: {} }
for (const path of data) {
const parts = path.split('/');
const file = parts.pop();
let branch = tree, partPath = '';
for (const part of parts) {
partPath += `${part}/`;
if (partPath === `${part}/`) {
tree.root[partPath] = (tree[partPath] ??= { name: part, children: [] });
} else if (tree[partPath] === undefined) {
tree[partPath] = { name: part, children: [] };
branch.children.push(tree[partPath]);
}
branch = tree[partPath];
}
branch.children.push({ name: file, id: path });
}
return {
name: "assets",
children: Object.values(tree.root)
}
}
const data = [
'files/photos/foo.png',
'files/photos/bar.png',
'files/videos/movie.mov',
'docs/photos/sd.jpg'
];
const result = mergeAssets(data);
console.log(JSON.stringify(result, null, 2))
I was able to find a solution using a recursive function. If others have any tips on how to improve this, I'd love to hear.
function mergeObjects(parentArray,path,originalName){
if(originalName === undefined){
originalName = path;
}
const parts = path.split("/");
var nextPart = "";
parts.forEach((part, index) => index > 0 ? nextPart += (nextPart !== "" ? "/" : "") + part : null);
//does the parentArray contain a child with our name?
const indexOfChild = parentArray.findIndex(child => child.name === parts[0]);
if(indexOfChild === -1){
//this item does not exist
if(parts.length > 1){
var index = parentArray.push({
name: parts[0],
children : []
}) - 1;
mergeObjects(parentArray[index].children,nextPart,originalName);
}else{
parentArray.push({
name: parts[0],
id : originalName
});
}
}else{
//this item already exists
if(parts.length > 1){
mergeObjects(parentArray[indexOfChild].children,nextPart,originalName);
}
}
}
And the function is called with the following:
function mergeAssets(assets){
var obj = {
name: "assets",
children: []
};
assets.forEach(asset => mergeObjects(obj.children,asset));
return obj;
}
I have an object like this
const test = {
'/blogs/architecture':
{
name: 'Architecture',
icon: 'archway',
iconCategory: 'fas',
slug: '/blogs/architecture'
}
}
Now I want find the slug field and I have only the name field. How can I find the slug by the name? please help
Try utilizing Object.values() with Array#find():
const test = {
'/blogs/architecture': {
name: 'Architecture',
icon: 'archway',
iconCategory: 'fas',
slug: '/blogs/architecture'
}
};
const findSlugByName = name => {
return Object.values(test).find(obj => obj.name === name)?.slug;
}
console.log(findSlugByName('Architecture'));
const test = {
'/blogs/architecture': {
name: 'Architecture',
icon: 'archway',
iconCategory: 'fas',
slug: '/blogs/architecture'
},
'/blogs/architecture2': {
name: 'Architecture2',
icon: 'archway',
iconCategory: 'fas',
slug: '/blogs/architecture'
}
}
const searchName = 'Architecture';
let searchResult;
const node = Object.values(test).forEach((node) => {
if(node.name === searchName) {
searchResult = node;
}
});
console.log(searchResult);
I have a config object. Using this config object, I populate required elements by appending a string to the key of this object.I need help updating values
const MEMBER_INITIAL_VALUE = {
type: '',
dateOfBirth_: '',
seekingCoverage_: true,
relationshipToPrimary: ''
};
const updateInitialValue = (type, relationshipToPrimary) => {
var newMemberObjValue = JSON.parse(JSON.stringify(MEMBER_INITIAL_VALUE));
let updateValue = Object.entries(newMemberObjValue).forEach(([key, value]) => {
[`${key}_${type}`]: value; //I'm stuck here. not sure how to proceed
delete key;
});
return updateValue;
};
updateInitialValue = ('applicant', 'SELF');
updateInitialValue = ('spouse', 'DEPENDANT');
Expected Result:
{
type: 'applicant',
dateOfBirth_applicant: '',
seekingCoverage_applicant: true
relationshipToPrimary: 'SELF'
};
{
type: 'spouse',
dateOfBirth_spouse: '',
seekingCoverage_spouse: true
relationshipToPrimary: 'DEPENDANT'
};
Since you're not updating the original object, you can simplify this greatly:
const MEMBER_INITIAL_VALUE = {
type: '',
dateOfBirth_: '',
seekingCoverage_: true,
relationshipToPrimary: ''
};
const updateInitialValue = (type, relationshipToPrimary) => ({
type,
relationshipToPrimary,
[`dateOfBirth_${type}`]: MEMBER_INITIAL_VALUE.dateOfBirth_,
[`seekingCoverage_${type}`]: MEMBER_INITIAL_VALUE.seekingCoverage_
});
let updatedValue = updateInitialValue('applicant', 'SELF');
updatedValue = updateInitialValue('spouse', 'DEPENDANT');
This should do the trick:
const MEMBER_INITIAL_VALUE = {
type: '',
dateOfBirth_: '',
seekingCoverage_: true,
relationshipToPrimary: ''
};
const updateInitialValue = (type, relationshipToPrimary) => {
let newMemberInitialValue = JSON.parse(JSON.stringify(MEMBER_INITIAL_VALUE));
Object.keys(newMemberInitialValue).forEach((key) => {
if(!['type', 'relationshipToPrimary'].includes(key)) {
newMemberInitialValue[`${key}_${type}`] = newMemberInitialValue[key];
delete newMemberInitialValue[key];
}
});
newMemberInitialValue.type = type;
newMemberInitialValue.relationshipToPrimary = relationshipToPrimary;
console.log(newMemberInitialValue);
};
let applicantValues = updateInitialValue('applicant', 'SELF');
let spouseValues = updateInitialValue('spouse', 'DEPENDANT');
EDIT: Missed returning the value from the function and then assigning to a new variable.
Although an answer was posted, because i also solved it and my solution is a bit different (though the other answer looks way too slimmer) i would post it here.
const MEMBER_INITIAL_VALUE = {
type: "",
dateOfBirth_: "",
seekingCoverage_: true,
relationshipToPrimary: "",
};
const updateInitialValue = (type, relationshipToPrimary) => {
var newMemberObjValue = JSON.parse(JSON.stringify(MEMBER_INITIAL_VALUE));
Object.entries(newMemberObjValue).forEach(([key, value]) => {
if (key === "type") {
newMemberObjValue[key] = type;
} else if (key === "dateOfBirth_") {
Object.defineProperty(
newMemberObjValue,
[`${key}_${type}`],
Object.getOwnPropertyDescriptor(newMemberObjValue, key)
);
delete newMemberObjValue[key];
newMemberObjValue[`${key}_${type}`] = value;
} else if (key === "seekingCoverage_") {
Object.defineProperty(
newMemberObjValue,
[`${key}_${type}`],
Object.getOwnPropertyDescriptor(newMemberObjValue, key)
);
delete newMemberObjValue[key];
newMemberObjValue[`${key}_${type}`] = value;
} else if (key === "relationshipToPrimary") {
newMemberObjValue[key] = relationshipToPrimary;
}
});
return newMemberObjValue;
};
const updatedValue1 = updateInitialValue("applicant", "SELF");
const updatedValue2 = updateInitialValue('spouse', 'DEPENDANT');
Though a few answers have already been posted, I would like to suggest a similar one that does the same thing in a much more clear and concise way:
function Member() {
this.type = '';
this.dateOfBirth = '';
this.seekingCoverage = true;
this.relationshipToPrimary = '';
}
function UpdateInitialValue(type, relationshipToPrimary) {
var newMember = new Member();
newMember.type = type;
newMember.relationshipToPrimary = relationshipToPrimary;
return newMember;
}
console.log(UpdateInitialValue('applicant', 'SELF'));
console.log(UpdateInitialValue('spouse', 'DEPENDANT'));
describe('YoutubeService.getTrendingVideos', function() {
it('should resolve to expectedResult', function() {
const params = {
id: 'O2uf_RveI80',
title:
'Shambho Shankara Full Movie - 2018 Telugu Full Movies - Shakalaka Shankar, Karunya',
thumbnail: 'https://i.ytimg.com/vi/O2uf_RveI80/hqdefault.jpg',
publishedAt: '2 days ago',
};
return chai.assert.isObject(getTrends.YoutubeService.getVideoDetails(params),'object match found');
});
Above is the test assertion written in chai for testing whether a function is returing object or not.
the function is as follows:
export class YoutubeService {
getTrendingVideos(country) {
var params = {
part: 'snippet',
chart: 'mostPopular',
regionCode: country, // should be replaced with country code from countryList
maxResults: '24',
key: config.youtubeApi.key
};
let result = [];
let promises = [];
return axios.get('/', {params}).then(function(res){
result = res.data.items;
for (var i = 0; i < result.length; i++) {
result[i] = {
id: result[i].id,
title: result[i].snippet.title,
thumbnail: result[i].snippet.thumbnails.high.url,
publishedAt: moment(result[i].snippet.publishedAt).fromNow()
};
promises.push(YoutubeService.getVideoDetails(result[i]));
}
return Promise.all(promises);
});
}
static getVideoDetails(video) {
let params = {
part: 'statistics',
id: video.id,
key: config.youtubeApi.key
};
return axios.get('/', {params}).then(function(res) {
let result = res.data;
video.viewCount = result['items'][0].statistics.viewCount;
video.likeCount = result['items'][0].statistics.likeCount;
return video;
});
}
}
I encounter the following problem:
expected {} to be an object
How can i solve it? I am new to testing in Mocha and Chai
Thanks in advance.
This is my first question on here. Doesn't appear to be asked elsewhere, but then again I'm not sure exactly how to phrase my question.
How can I transform an array that looks like this:
var message = {
pay_key: '12345',
'transaction[0].sender_id': 'abc',
'transaction[0].is_primary_receiver': 'false',
'transaction[0].id': 'def',
'transaction[1].sender_id': 'xyz',
'transaction[1].is_primary_receiver': 'false',
'transaction[1].id': 'tuv',
};
into something like this:
{
pay_key : '12345',
transaction : [
{
sender_id : 'abc',
is_primary_receiver : 'false',
id : 'def'
},
{
sender_id : 'xyz',
is_primary_receiver : 'false',
id : 'tuv'
}
]
}
I have no control over the format of the first object as it comes from an external service. I am trying to insert the message object into a MongoDB collection, but when I try to do an insert as-is, I get an error. So I'm trying to put it into the correct form.
Should I be using Underscore for this? I've played around with _.each but can't get it to work.
my take..
var message = {
pay_key: '12345',
'transaction[0].sender_id': 'abc',
'transaction[0].is_primary_receiver': 'false',
'transaction[0].id': 'def',
'transaction[1].sender_id': 'xyz',
'transaction[1].is_primary_receiver': 'false',
'transaction[1].id': 'tuv',
};
message.transaction=[];
for (var p in message) {
var m = p.match(/^transaction\[(\d+)\]\.(.*)/);
if (m&&m[1]&&m[2]) {
message.transaction[m[1]]=message.transaction[m[1]]||{};
message.transaction[m[1]][m[2]]=message[p];
delete message[p];
}
}
Here's a generic function I just whipped up
function makeObject(message) {
var retObj = {},
makePath = function (p, pos) {
if (/\[\d+\]$/.test(p)) {
var q = p.split(/[\[\]]/),
r = q[0],
s = q[1];
if (!pos[r]) {
pos[r] = [];
}
return pos[r][s] = pos[r][s] || {};
}
return pos[p] = pos[p] || {};
};
for(var k in message) {
if (message.hasOwnProperty(k)) {
if (k.indexOf('.') < 0) {
retObj[k] = message[k];
}
else {
var path = k.split('.'),
pos = retObj,
last = path.pop();
path.forEach(function(p) {
pos = makePath(p, pos);
});
pos[last] = message[k];
}
}
}
return retObj;
}
It works as required, but I'm sure there's some better code to do it
Had a similar response, so adding it anyway:
Object.keys(message).forEach(function(key) {
var keySplit = key.split( /\[|\]\./g )
if ( keySplit.length != 1 ) {
if ( !message.hasOwnProperty(keySplit[0]) )
message[keySplit[0]] = [];
message[keySplit[0]][keySplit[1]] = message[keySplit[0]][keySplit[1]]||{};
message[keySplit[0]][keySplit[1]][keySplit[2]] = message[key];
delete message[key];
}
});