I have an array of (could be more than this), that has a uid and a timestamp.
My goal is to cycle through an object and if their uid is equal to each other, only keep the object with the greater timestamp.
[
{
"uid":"u55555",
"timestamp":1536273731,
"id":"8a655addf1293b6d780ff6469c0848dd",
"name":"John Doe",
},
{
"uid":"u55555",
"timestamp":1536273831,
"id":"8v8799817981mcmccm89c81282128cm2",
"name":"John Doe",
},
{
"uid":"u1111",
"timestamp":1536253940,
"id":"c8898202n2nu929n2828998228989h2h2",
"name":"Test Testerson",
},
{
"uid":"u55555",
"timestamp":1536274940,
"id":"fb990b1734e4aaea2e39315952e13123",
"name":"John Doe",
},
{
"uid":"u11111",
"timestamp":1538275741,
"id":"99s9hshs88s8g89898899898897a79s",
"name":"Test Testerson",
},
]
Does anyone know how I would do this?
I've been playing around with the following but can't get it just right.
var result = signatures.filter(function (a) {
//logic here
}, Object.create(null));
You could sort the original array by timestamp and then reduce it to only a set of unique uids using sort and reduce.
var data = [{"uid": "u55555","timestamp": 1536273731,"id": "8a655addf1293b6d780ff6469c0848dd","name": "John Doe",}, { "uid": "u55555", "timestamp": 1536273831, "id": "8v8799817981mcmccm89c81282128cm2", "name": "John Doe", }, { "uid": "u1111", "timestamp": 1536253940, "id": "c8898202n2nu929n2828998228989h2h2", "name": "Test Testerson", }, { "uid": "u55555", "timestamp": 1536274940, "id": "fb990b1734e4aaea2e39315952e13123", "name": "John Doe", }, { "uid": "u11111", "timestamp": 1538275741, "id": "99s9hshs88s8g89898899898897a79s", "name": "Test Testerson", }];
var result = data
.sort((a,b) => b.timestamp - a.timestamp) //Sort by timestamp descending
.reduce((a,i) => a.some(n=>n.uid === i.uid) ? a : [...a, i], []); //If item is already accounted for, ignore it
console.log(result);
You can create an object keyed to the guid and loop through your array adding the item to the object if it either isn't already there or the time is smaller. Then just take the values from that object:
let arr = [{"uid":"u55555","timestamp":1536273731,"id":"8a655addf1293b6d780ff6469c0848dd","name":"John Doe",},{"uid":"u55555","timestamp":1536273831,"id":"8v8799817981mcmccm89c81282128cm2","name":"John Doe",},{"uid":"u1111","timestamp":1536253940,"id":"c8898202n2nu929n2828998228989h2h2","name":"Test Testerson",},{"uid":"u55555","timestamp":1536274940,"id":"fb990b1734e4aaea2e39315952e13123","name":"John Doe",},{"uid":"u11111","timestamp":1538275741,"id":"99s9hshs88s8g89898899898897a79s","name":"Test Testerson",},]
let newArr = Object.values(
arr.reduce((obj, item) => {
if (!obj[item.uid] || obj[item.uid].timestamp < item.timestamp)
obj[item.uid] = item
return obj
}, {}))
console.log(newArr)
You could find the object and check the timestamp or add the actual object to the result set.
var array = [{ uid: "u55555", timestamp: 1536273731, id: "8a655addf1293b6d780ff6469c0848dd", name: "John Doe" }, { uid: "u55555", timestamp: 1536273831, id: "8v8799817981mcmccm89c81282128cm2", name: "John Doe" }, { uid: "u1111", timestamp: 1536253940, id: "c8898202n2nu929n2828998228989h2h2", name: "Test Testerson" }, { uid: "u55555", timestamp: 1536274940, id: "fb990b1734e4aaea2e39315952e13123", name: "John Doe" }, { uid: "u11111", timestamp: 1538275741, id: "99s9hshs88s8g89898899898897a79s", name: "Test Testerson" }],
result = array.reduce((r, o) => {
var index = r.findIndex(({ uid }) => uid === o.uid);
if (index === -1) {
return r.concat(o);
}
if (o.timestamp > r[index].timestamp) {
r[index] = o;
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This creates a new Object, which uses keys based on the UID; then populates it with only the last entries. Perhaps not the smallest code possible, but it's a method.
let sorted = {};
let original = [{
"uid": "u55555",
"timestamp": 1536273731,
"id": "8a655addf1293b6d780ff6469c0848dd",
"name": "John Doe",
},
{
"uid": "u55555",
"timestamp": 1536273831,
"id": "8v8799817981mcmccm89c81282128cm2",
"name": "John Doe",
},
{
"uid": "u11111",
"timestamp": 1536253940,
"id": "c8898202n2nu929n2828998228989h2h2",
"name": "Test Testerson",
},
{
"uid": "u55555",
"timestamp": 1536274940,
"id": "fb990b1734e4aaea2e39315952e13123",
"name": "John Doe",
},
{
"uid": "u11111",
"timestamp": 1538275741,
"id": "99s9hshs88s8g89898899898897a79s",
"name": "Test Testerson",
},
];
original.forEach((item) => {
if (sorted[item.uid] == undefined || sorted[item.uid].timestamp < item.timestamp) {
// if key doesn't exist, create it
// if key exists but timestamp is newer, replace it
sorted[item.uid] = {
uid: item.uid,
timestamp: item.timestamp,
id: item.id,
name: item.name
}
}
});
console.log(sorted);
Related
I'm looking for a way in javascript to transform this json to something else.
{
"John Doe": {
"place": "Amsterdam"
},
"Jane Doe": {
"place": "Paris"
}
}
To something like this:
{
{ "id": 0,
"name": "John Doe",
"place": "Amsterdam"
},
{ "id": 1,
"name": "Jane Doe",
"place": "Paris"
},
}
How can I achieve this with javascript?
You can use Object.entries to get key/value pair and use map method to transform the object into the new one.
const data = {
"John Doe": {
"place": "Amsterdam"
},
"Jane Doe": {
"place": "Paris"
}
}
const result = Object.entries(data).map(([key, value], index) => ({
id: index,
name: key,
place: value.place
}))
console.log(result)
You can map the entries to objects. You can mix destructuring and object property shorthand to simplify this greatly.
Note: Order is not guaranteed when iterating through an object's keys.
const obj = {
"John Doe": { "place": "Amsterdam" },
"Jane Doe": { "place": "Paris" },
};
const list = Object.entries(obj)
.map(([name, { place }], id) =>
({ id, name, place }));
console.log(list);
.as-console-wrapper { top: 0; max-height: 100% !important; }
i want to remove duplicates from javascript 'objects array' based on object property value
var data = [
{
"John Doe": "john33#gmail.com",
},
{
"William Smith": "william65#gmail.com",
},
{
"Robert Johnson": "robert99#gmail.com",
},
{
"John Smith": "john33#gmail.com",
},
{
"James Johnson": "james8#gmail.com",
},
];
here in the 'data' array there are same emails for "John Doe" and "John Smith", i want to remove one object of theme.
This can be done with Array.reduce(), combined with Object.values() as follows:
var data = [
{
"John Doe": "john33#gmail.com",
},
{
"William Smith": "william65#gmail.com",
},
{
"Robert Johnson": "robert99#gmail.com",
},
{
"John Smith": "john33#gmail.com",
},
{
"James Johnson": "james8#gmail.com",
},
];
const result = data.reduce((acc, o) => {
if (!acc.map(x => Object.values(x)[0]).includes(Object.values(o)[0])) {
acc.push(o);
}
return acc;
}, []);
console.log(result);
I need to flatten the json, but want to consider an exclusion_keys_array list which are not to be processed/added to the list
for example
if I have an exclusion_keys_array = ["addresses.metadata", "pageToken"]
//only metadata of addresses will be skipped (second level skip)
if I have an exclusion_keys_array = ["metadata", "pageToken"]
//metadata of parent json will be skipped (top level key skip)
How do I flatten a JSON using an exclusion array?
Code source: Dynamically generate a 2d array from JSON with varying columns
var exlusion_list = ["metadata", "meta", "pageToken"];
var crowds = [{
"name": [{
"firstName": "John",
"middleName": "Joseph",
"lastName": "Briggs",
}],
"addresses": [{
"type": "home",
"poBox": "111",
"city": "City1",
"postalCode": "1ER001",
"country": "USA",
}, {
"type": "work",
"poBox": "222",
"city": "City2",
"region": "Region2",
"postalCode": "1ER002",
}],
"photos": [{
"url": "photo.org/person1",
"default": true,
}, {
"url": "imagur.org/person1",
"default": true,
}],
"metadata": [{
"meta-id": "1234",
}],
}, {
"name": [{
"firstName": "Bill",
"lastName": "Thatcher",
}],
"addresses": [{
"type": "home",
"city": "City3",
"region": "Region3",
"postalCode": "1ER003",
"country": "USA",
}, {
"type": "work",
"poBox": "444",
"region": "Region4",
"postalCode": "1ER004",
}, {
"poBox": "555",
"region": "Region5",
"postalCode": "1ER005",
}],
"metadata": [{
"meta-id": "1234",
}],
}];
function flatten(obj, res = {}, key = '') {
let add = (d, s) => key ? key + d + s : s;
if (Array.isArray(obj)) {
obj.forEach((v, n) => flatten(v, res, add(' #', n + 1)));
} else if (typeof obj === 'object') {
Object.entries(obj).forEach(([k, v]) => flatten(v, res, add(': ', k)));
} else {
res[key] = obj;
}
return res;
}
let flats = crowds.map(obj => flatten(obj));
function combineKeys(objs) {
let keys = objs.reduce((k, obj) => k.concat(Object.keys(obj)), []);
return [...new Set(keys)];
}
let keys = combineKeys(flats);
let table = flats.map(f => keys.map(k => f[k] ?? ''));
table.unshift(keys);
console.log({ table });
// document.write(JSON.stringify(table));
.as-console-wrapper { min-height: 100%!important; top: 0; }
// .as-console-wrapper { min-height: 70%!important; bottom: 0; }
A quick fix would be filter the keys like below. I think there is a more efficient way to do it but I didn't look into the codes too deep.
let keys = combineKeys(flats).filter(
key => !exlusion_list.includes(key.split(":")[0].split(" ")[0])
);
I am reading a simple data set from a data.txt file. I would like to take this data and transform it into a specific object as per my example below. I have managed to get it into a somewhat usable JSON object but this is not ideal. I have included an example of the desired object.
Here is my app.js file:
let output = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
customers.push({
name: line[0],
product: [{
item: line[1],
serial: line[2],
year: line[3]
}]
})
return customers
}, [])
console.log(JSON.stringify(output, null, 2))
This currently the above NodeJs code returns the following array object:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
}
]
},
{
"name": "Nancy",
"product": [
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
}
]
},
{
"name": "John",
"product": [
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
What I am trying to do is get the below object returned - ideally still following the same functional approach:
[
{
"name": "Nancy",
"product": [
{
"item": "Macbook Pro",
"serial": "A34D05980FCD4303",
"year": "2019"
},
{
"item": "iPad",
"serial": "O0403X3028423C92",
"year": "2015"
},
{
"item": "iPhone",
"serial": "X3830238S3309230",
"year": "2017"
}
]
},
{
"name": "John",
"product": [
{
"item": "Macbook Pro",
"serial": "X2020J393983H380",
"year": "2013"
},
{
"item": "iPhone",
"serial": "X38320093X032309",
"year": "2015"
}
]
},
{
"name": "fluffikins",
"product": [
{
"item": "iMac",
"serial": "F392D392033X3232",
"year": "2013"
},
{
"item": "iPad",
"serial": "FE322230D3223S21",
"year": "2011"
}
]
}
]
Here is my mock data set that lives in data.txt
Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011
Instead of an array you can use Map in reduce as accumulator, use name as key in Map and club value of all keys, finally just get the values Map to get desired output
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`
const final = data.split('\n')
.map(v => v.split(';'))
.reduce((op, [name, item, serial, year]) => {
let obj = { item, serial, year }
if (op.has(name)) {
op.get(name).products.push(obj)
} else{
op.set(name,{name, products:[obj]})
}
return op
}, new Map())
console.log([...final.values()])
Here is a "functional version" that utilizes a Map to find duplicates in O(1):
(map => (
fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n')
.map((line) => line.split(';'))
.forEach(([name, item, serial, year]) =>
map.has(name)
? map.get(name).product.push({ item, serial, year })
: map.set(name, { name, product: [{ item, serial, year }] })
),
[...map.values()]
)(new Map)
But seriously, whats so bad about imperative style?:
const customers = new Map;
const entries = fs.readFileSync('./data.txt', 'UTF8')
.trim()
.split('\r\n');
for(const entry of entries) {
const [name, item, serial, year] = entry.split(";");
const product = { item, serial, year };
if(customers.has(name)) {
customers.get(name).product.push(product);
} else customers.set(name, { name, product: [product] });
}
const result = [...customers.values()];
You can modify the .reduce function to only add a new item to the array if there isn't one with that name. If there is, just add the product to that item's product array.
const data = `Nancy;Macbook Pro;A34D05980FCD4303;2019
Nancy;iPad;O0403X3028423C92;2015
Nancy;iPhone;X3830238S3309230;2017
John;Macbook Pro;X2020J393983H380;2013
John;iPhone;X38320093X032309;2015
fluffikins;iMac;F392D392033X3232;2013
fluffikins;iPad;FE322230D3223S21;2011`;
const result = data.trim()
.split('\n')
.map((line) => line.split(';'))
.reduce((customers, line) => {
const product = {
item: line[1],
serial: line[2],
year: line[3]
};
const customer = customers.find(({
name
}) => name === line[0]);
if (customer) {
customer.product.push(product);
} else {
customers.push({
name: line[0],
product: [product]
});
}
return customers
}, []);
console.log(result);
I have the following events array. For every event there is a hash as {organisation name: [{participant 1}, {participant 2}, {...}]}
"events": [
{
"Org A": [
{
"event_id": 1,
"id": 432,
"name": "John Doe",
"role": null
},
{
"event_id": 1,
"id": 312,
"name": "Jane Mow",
"role": [
"speaker"
]
}
],
}
],
I would like to filter this events array to only contain participants whose role contains speaker.
Also, when there are no speakers in the participant array, the respective organisation entry needs to be removed from the Hash (object).
To filter the array of objects, I tried using this:
_.each(events, function(event){
_.filter(event, function(p) {
_.filter(p, function(d){
return _.some(d.role, function(r){
return r == "speaker"})
})
})
})
This however doesn't work.
Try this
var data = {
"events": [{
"Org A": [{
"event_id": 1,
"id": 432,
"name": "John Doe",
"role": null
}, {
"event_id": 1,
"id": 312,
"name": "Jane Mow",
"role": [
"speaker"
]
}],
"Org B": [],
"Org C": []
}]
};
var SPEAKER = 'speaker';
var result = _.map(data.events, function (events) {
return _.chain(events)
.mapObject(function (value, key) {
return _.filter(value, function (event) {
return _.isArray(event.role) && _.indexOf(event.role, SPEAKER) >= 0;
});
})
.pick(function (value) {
return value && value.length;
})
.value();
})
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>