how to loop on object and split it by ":" into separate one
{
labs: [1,2,":",3,4],
level: [1,2,":",3,4]
}
Expected Output:
{
labs: [1,2],
level: [1,2]
}
{
labs: [3,4],
level : [3,4]
}
You can use itertools.groupby from the standard library to group the numbers that are not ":". With that you can use zip to pair off the groups.
from itertools import groupby
d = {
"labs": [1,2,":",3,4],
"level": [10,20,":",30,40]
}
groups = [[(k, list(g)) for b, g in groupby(v, key=lambda n:n != ':') if b]
for k, v in d.items()
]
list(map(dict, zip(*groups)))
# [
# {'labs': [1, 2], 'level': [10, 20]},
# {'labs': [3, 4], 'level': [30, 40]}
# ]
This should work with arbitrary data. For example with input like:
d = {
"labs": [1,2,":",3,4,":", 5, 6],
"level": [10,20,":",30,40,":",50, 60],
"others":[-1,-2,":",-3,-4,":",-5,-6]
}
You will get:
[{'labs': [1, 2], 'level': [10, 20], 'others': [-1, -2]},
{'labs': [3, 4], 'level': [30, 40], 'others': [-3, -4]},
{'labs': [5, 6], 'level': [50, 60], 'others': [-5, -6]}
]
But it does expect the lists to be the same length because the way zip() works. If that's not a good assumption you will need to decide what to do with uneven lists. In that case itertools.zip_longest() will probably be helpful.
Use javaScript to resolve this problem, maybe the code is not the best
const obj = {
labs: [1,2,":",3,4,":",5,6],
level: [1,2,":",3,4,":",7,8],
others: [1,2,":",3,4,":",9,10]
}
const format = (obj = {}, result = []) => {
const keys = Object.keys(obj);
for ( key of keys) {
const itemValues = obj[key].toString().split(':');
let tempRes = {}
itemValues.map((itemValue, index) => {
Object.assign(tempRes, {
[`${keys[index]}`]: itemValue.replace(/^(,)+|(,)+$/g, '').split(',').map(Number)// you can format value here
})
})
result.push(tempRes);
}
return result;
}
console.log(format(obj))
You will get
[
{ labs: [ 1, 2 ], level: [ 3, 4 ], others: [ 5, 6 ] },
{ labs: [ 1, 2 ], level: [ 3, 4 ], others: [ 7, 8 ] },
{ labs: [ 1, 2 ], level: [ 3, 4 ], others: [ 9, 10 ] }
]
Related
I am trying to figure out how to map a new array of objects that kind of creates teams by checking each array of users and, where there is a common users, moving that entire array into a new property that also features the notebookIds in common.
I have an array of objects structured like so:
const usersByNotebooks =
[
{
"notebookId": "abc",
"users": [1, 2, 3, 4]
},
{
"notebookId": "cde",
"users": [2, 3, 4]
},
{
"notebookId": "fgh",
"users": [3, 4, 5]
},
{
"notebookId": "qqq",
"users": [33, 16, 12]
},
]
So for the above data it would become something like this:
const teams =
[
{
"notebooksOnTeam": ["abc", "cde", "fgh"],
"usersOnTeam": [1, 2, 3, 4, 5]
},
{
"notebooksOnTeam": "qqq",
"usersOnTeam": [33, 16, 12]
},
]
I am using javascript and having trouble getting the logic down.
Loop over objects of array using reduce and check:
If the current notebook's users don't match any existing team with find method, so create a new team.
If the current notebook's users match an existing team, add the notebook to that team.
const usersByNotebooks = [{ "notebookId": "abc", "users": [1, 2, 3, 4] }, { "notebookId": "cde", "users": [2, 3, 4] }, { "notebookId": "fgh", "users": [3, 4, 5] }, { "notebookId": "qqq", "users": [33, 16, 12] }, ];
const teams = usersByNotebooks.reduce((result, current) => {
const teamFound = result.find((team) => team.usersOnTeam.some((user) => current.users.includes(user)));
if (!teamFound) {
result.push({
notebooksOnTeam: [current.notebookId],
usersOnTeam: current.users
});
} else {
teamFound.notebooksOnTeam.push(current.notebookId);
current.users.forEach((user) => {
if (!teamFound.usersOnTeam.includes(user)) {
teamFound.usersOnTeam.push(user);
}
});
}
return result;
}, []);
console.log(teams)
You could have a look to any objects of the result set and either get the first object of the same group and add all other found and finally add the actual value or later add a new object.
This approach works for unsorted and not connected items which gets later a joint.
const
addIfNotExist = (array, value) => array.includes(value) || array.push(value),
usersByNotebooks = [{ notebookId: "abc", users: [1, 2, 3, 4] }, { notebookId: "cde", users: [2, 3, 4] }, { notebookId: "fgh", users: [3, 4, 5] }, { notebookId: "qqq", users: [33, 16, 12] }, { notebookId: "xxx", users: [6, 7] }, { notebookId: "yyy", users: [5, 6] }],
result = usersByNotebooks.reduce(
(r, { notebookId, users }) => users.reduce((s, user) => {
const objects = [];
let first;
for (const o of s) {
if (!o.users.includes(user) && !o.notebooks.includes(notebookId)) {
objects.push(o);
continue;
}
if (!first) objects.push(first = o);
o.users.forEach(addIfNotExist.bind(null, first.users));
o.notebooks.forEach(addIfNotExist.bind(null, first.notebooks));
}
if (first) {
addIfNotExist(first.users, user);
addIfNotExist(first.notebooks, notebookId);
} else {
objects.push({ users: [user], notebooks: [notebookId] });
}
return objects;
}, r),
[]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This is an abstract solution for any length of groups which are connected.
It works in three step:
Generate an array of pairs or more or less items in a tupel,
group connected items together in an aray of arrays and
map the items in the wanted format.
const
addIfNotExist = (array, value) => array.includes(value) || array.push(value),
groupConnectedParts = (r, a) => {
const objects = [];
let first;
for (const b of r) {
if (!a.some((v, i) => b[i].includes(v))) {
objects.push(b);
continue;
}
if (!first) objects.push(first = b);
b.forEach((group, i) => group.forEach(addIfNotExist.bind(null, first[i])));
}
if (first) a.forEach((v, i) => addIfNotExist(first[i], v));
else objects.push(a.map(v => [v]));
return objects;
},
usersByNotebooks = [{ notebookId: "abc", users: [1, 2, 3, 4] }, { notebookId: "cde", users: [2, 3, 4] }, { notebookId: "fgh", users: [3, 4, 5] }, { notebookId: "qqq", users: [33, 16, 12] }, { notebookId: "xxx", users: [6, 7] }, { notebookId: "yyy", users: [5, 6] }],
result = usersByNotebooks
.flatMap(({ notebookId, users }) => users.map(user => [notebookId, user]))
.reduce(groupConnectedParts, [])
.map(([notebooks, users]) => ({ notebooks, users }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Let's say I have the following data
[
{ name: 'A', values: [1, 2, 3 ,4] },
{ name: 'B', values: [5, 6, 7, 8] }
]
and I have a mongodb that has the following items in a collection:
#1 { name: 'A', values: [1, 2, 3 ,4], path: '...' },
#2 { name: 'B', values: [8, 9, 5, 7], path: '...' },
#3 { name: 'B', values: [5, 6, 7, 8], path: '...' },
#4 { name: 'C', values: [9, 10, 11, 12], path: '...' }
Now I want to query the paths that match my 2 items A and B from the data (Items #1 and #3). Is that possible edit: with a single query?
You can loop through the data and use query inside the map function by making it asynchronous
const data = [
{ name: 'A', values: [1, 2, 3 ,4] },
{ name: 'B', values: [5, 6, 7, 8] }
]
const result = []
await Promise.all(data.map(async(d) => {
result.push(await db.collection.findOne(d))
}))
Or even with the single query
await db.collection.find(
{
name: { $in: data.map(({ name }) => name) },
values: { $in: data.map(({ values }) => values) }
}
)
I have an array. And i want to convert them into a group of objects.
below is my array
[ null,
[ 5, 6 ],
[ 7, 8 ],
[ 9, 10 ],
[ 13, 14 ] ]
Then i tried them to convert into object by pairs but what i had was this:
{ '0': null,
'1': [ 5, 6 ],
'2': [ 7, 8 ],
'3': [ 9, 10 ],
'4': [ 13, 14 ] }
What i'm trying to achieve is something like below:
{
"0": 5,
"1": 6,
},
{
"0": 7,
"1": 8,
},
{
"0": 9,
"1": 10,
},
{
"0": 13,
"1": 14,
},
thank you for those who will help
You could filter falsy values and map objects where you have assigned the array.
var array = [null, [5, 6], [7, 8], [9, 10], [13, 14]],
result = array
.filter(Boolean)
.map(a => Object.assign({}, a));
console.log(result);
Wrapped in a function
function getObjects(array) {
return array
.filter(Boolean)
.map(a => Object.assign({}, a));
}
console.log(getObjects([null, [5, 6], [7, 8], [9, 10], [13, 14]]));
You should have a condition that skip the null value in the array:
function changeArray(arr){
var res = [];
arr.forEach((item)=>{
let obj = {};
if(item){
item.forEach((val, index)=>{
obj[index] = val;
});
res.push(obj);
}
});
return res;
}
var arr1 = [ null,
[ 5, 6 ],
[ 7, 8 ],
[ 9, 10 ],
[ 13, 14 ] ];
console.log(changeArray(arr1));
var arr2 = [ null,
[ 5, 6, 7 ],
[ 7, 8, 9 ]];
console.log(changeArray(arr2));
I have an array which can be nested multiple times. However, always two arrays with two entries each are at the end of each "nesting". I always need the two entries from the two arrays at the end of each nesting returned.
Here is an example:
const arr = [
[
[1, 2], [3, 4]
], [
[5, 6], [7, 8]
], [
[
[9, 10], [11, 12]
], [
[14, 15], [16, 17]
]
]
];
Here is the expected result:
const return1 = [
{ a: 1, b: 2 },
{ a: 3, b: 4 }
];
const return2 = [
{ a: 5, b: 6 },
{ a: 7, b: 8 }
];
const return3 = [
{ a: 9, b: 10 },
{ a: 11, b: 12 }
];
const return4 = [
{ a: 13, b: 14 },
{ a: 15, b: 16 }
];
Everything I find online is how to reduce an n-nested array to a flat array, something like this:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
You could map with an iterative and recursive approach while checking nested arrays.
var array = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[[9, 10], [11, 12]], [[14, 15], [16, 17]]]],
result = array.reduce(function iter(r, a) {
return r.concat(Array.isArray((a[0] || [])[0])
? a.reduce(iter, [])
: [a.map(([a, b]) => ({ a, b }))]
);
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
With custom recursive function:
var arr = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[[9, 10], [11, 12]], [[14, 15], [16, 17]]]],
result = [],
get_pairs = function(arr, r){
arr.forEach(function(v){
if (Array.isArray(v)) {
if (!Array.isArray(v[0])) {
var o = {a: v[0], b: v[1]};
(!r.length || r[r.length-1].length==2)? r.push([o]) : r[r.length-1].push(o);
} else {
get_pairs(v, r);
}
}
});
};
get_pairs(arr, result);
console.log(result);
Spent to much time in this. However, here is a very messy looking code.
There is this recursive function that checks if a given array is in the form [[number, number],[number, number]]. If so, it adds an object to the variable returnArray that we are knowingly mutating.
If it is not in the form, we just check for the items inside the array.
const arrInput = [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]],
[
[[9, 10], [11, 12]],
[[14, 15], [16, 17]],
],
];
function mapArrayToObj(arr, returnArray = []) {
if (arr.length === 2 && typeof arr[0][0] === "number" &&
typeof arr[0][1] === "number" && typeof arr[1][0] === "number" &&
typeof arr[1][1] === "number") {
returnArray.push([
{ a: arr[0][0], b: arr[0][1] },
{ a: arr[1][0], b: arr[1][1] }
]);
} else {
arr.forEach((item) => { mapArrayToObj(item, returnArray); });
}
return returnArray;
}
console.log(mapArrayToObj(arrInput));
The code in python is:
def trimTree(tree):
p=tree[1]
if type(p) == type(""): return p
else :
return(trimTree(p[0]),trimTree(p[1]))
where tree is:
[
13,
[ 6, [ 3, [Object], [Object] ], [ 3, 'a' ] ],
[ 7, [ 3, 'b' ], [ 4, [Object], [Object] ] ]
]
when I convert I got error:
TypeError: Cannot read property '0' of undefined
What should I do?
With a proper data structure, which means any node has only a length of two elements, you get a list of values in breaths first order (the result is here a string).
function trimTree(tree) {
var p = tree[1];
return typeof p === 'string'
? p
: trimTree(p[0]) + trimTree(p[1]);
}
var data = [
13,
[
[6,
[
[3,
[
[1, 'X'],
[2, 'Y']
]
],
[3, 'a']
]
],
[7,
[
[3, 'b'],
[4,
[
[2, 'Z'],
[2, 'Q']
]
]
]
]
]
];
console.log(trimTree(data));