I'm practicing how to maniupulate data in JS in this article: http://learnjsdata.com/combine_data.html
var articles = [
{"id": 1, "name": "vacuum cleaner", "weight": 9.9, "price": 89.9, "brand_id": 2},
{"id": 2, "name": "washing machine", "weight": 540, "price": 230, "brand_id": 1},
{"id": 3, "name": "hair dryer", "weight": 1.2, "price": 24.99, "brand_id": 2},
{"id": 4, "name": "super fast laptop", "weight": 400, "price": 899.9, "brand_id": 3}
];
var brands = [
{"id": 1, "name": "SuperKitchen"},
{"id": 2, "name": "HomeSweetHome"}
];
articles.forEach(function(article) {
var result = brands.filter(function(brand){
return brand.id === article.brand_id;
});
delete article.brand_id;
article.brand = (result[0] !== undefined) ? result[0].name : null;
});
I'm confused with the last part: article.brand = (result[0] !== undefined) ? result[0].name : null;
I understand the conditional operation: it wants to have null value if result[0] is not defined. But I'm wondering what result[0] refers to. I thought it would take first object: {"id":2, "name": "HomeSweetHome"} so there should be for loop to iterate all objects in order to see if objects meet the condition? Could you inform me what I'm missing or/and what result[0] refers to?
Thanks,
result[0] will be undefined in case there is no element in result. result is expected to be an array of brands filtered by the filter operation
The filtered array result will have same brand as that of the current article in the outer foreach loop. The filter condition is going to achieve that.
It looks like in this particular case you will get only one element in result array always as there are unique brand ids. It might have more elements in case of duplicated brand ids.
result[0] points to first element in the array result
Related
Still learning here. This one as simple as it seems, has beaten me up. I have managed to get the answer. But, when I do, I am getting more than one name coming out of my if statement. I used a new set to remove the duplicate names in the names array. But frankly, that seems lazy to me and I feel something can be done that is better.
Can someone show me some ways I'm missing to better go through this problem? I tried flattening and that didn't work either. Thank you for your help!
Here are the directions given to me:
Create a function passingStudents that accepts an array of student objects.
It should iterate through the list of students and return an array of the names of all the students who have an average grade of at least 70.
function passingStudents(students) {
const names = [];
students.forEach(student => {
student.grades.forEach(grade => {
if(grade.score >= 70) {
names.push(student.name);
}
});
});
let uniqueChars = [...new Set(names)];
return uniqueChars;
}
//Uncomment the lines below to test your function:
var students = [
{
"name": "Marco",
"id": 12345,
"grades": [{"id": 0, "score": 65}, {"id": 1, "score": 75}, {"id": 2, "score": 85}]
},
{
"name": "Donna",
"id": 55555,
"grades": [{"id": 0, "score": 100}, {"id": 1, "score": 100}, {"id": 2, "score": 100}]
},
{
"name": "Jukay",
"id": 94110,
"grades": [{"id": 0, "score": 65}, {"id": 1, "score": 60}, {"id": 2, "score": 65}]
}
];
console.log(passingStudents(students)); // => [ 'Marco', 'Donna' ]
The reason your solution introduces multiple people in the names array is that it adds the name for each grade they have that is at least 70. This means it will return a student if any of their grades is at least 70 rather than if their average grade is at least 70. While your solution may pass the test case provided, it will not work for every case in general. A better solution is to average the grades by using reduce and filter the original list of students based on whether their average is above 70. Then you can map the filtered students to their name.
function passingStudents(students) {
return students
.filter((student) => {
const { grades } = student;
const average = grades.reduce((sum, grade) => sum + grade.score, 0) / grades.length;
return average >= 70;
})
.map((student) => student.name);
}
I am searching for an algorithm to reorder an list of dictionarys or in javascript array of objects.
For example I have the following list of objects:
my_dict = [
{
"id": 123,
"priority": 1
},
{
"id": 234,
"priority": 2
},
{
"id": 345,
"priority": 3
},
{
"id": 654,
"priority": 4
}
]
Now I want to change the item with id 654 to be the first priority. So the other items gets automatically to priority 2,3 and 4.
This should be the result:
my_dict = [
{
"id": 654,
"priority": 1
}
{
"id": 123,
"priority": 2
},
{
"id": 234,
"priority": 3
},
{
"id": 345,
"priority": 4
},
]
Another example is when I want to decrease the priority of item 234 to priority 3 then the item with priority 3 should become priority 2 (from the original/first dict). There are should no priority be twice in this list and there should not be gaps.
my_dict = [
{
"id": 123,
"priority": 1
},
{
"id": 345,
"priority": 2
},
{
"id": 234,
"priority": 3
},
{
"id": 654,
"priority": 4
}
]
For clarification here is an other example.
If I move item with id 123 to priority 4 the item before should become priority 1,2 and 3.
my_dict = [
{
"id": 234,
"priority": 1
},
{
"id": 345,
"priority": 2
},
{
"id": 654,
"priority": 3
}
{
"id": 123,
"priority": 4
},
]
The list should always start with priority 1. Can somebody explain how I can implement it with python or javascript? I tried it with a for loop starting and 1 but this does not work.
The discussions about a better data structure are spot-on. But if you still want to implement what you asked for, we can write a straightforward JS version that does the naive thing:
const changePriority = (xs, id, to,
idx = xs .findIndex (({id: i}) => i == id),
ys = [...xs .slice (0, idx), ...xs .slice (idx + 1)]
) =>
[ ...ys . slice (0, to - 1), xs [idx], ...ys .slice(to - 1)]
.map ((x, i) => ({...x, priority: i + 1}))
const dict = [{id: 123, priority: 1}, {id: 234, priority: 2}, {id: 345, priority: 3}, {id: 654, priority: 4}]
console .log (
changePriority (dict, 654, 2)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
Note that this depends upon your id and the new priorty, to actually existing in the input. It wouldn't be hard to add error-checking.
Also note that this returns a new array, and doesn't mutate the original; we're not barbarians here.
I disagree with the idea of having priority be represented by both the position in the list and the "priority" member. This is redundant and will cause trouble at some point.
Further, I have to make assumptions to answer this question, as the question is not complete.
Assumptions:
In the end, the list should be sorted by priority again
Priorities should end up being integers
Priorities always start at 1 and enumerate the list without gaps
First approach
Specify exactly where you want to put your item by using halfs. This is simple and everything else should fall in place.
Example
Task: Move 234 to priority 3.
Sadly, it is not uniquely defined what this is supposed to mean, as it is unclear where the old item of priority 3 should move to.
Instead move it to priority 3.5 to make it unambiguous, then re-sort and re-enumerate:
# Change priority of '234' to '3.5'
my_dict[1]["priority"] = 3.5
# Sort
my_dict.sort(key=lambda x: x["priority"])
# Re-enumerate
for (position, item) in enumerate(my_dict):
item["priority"] = position + 1
print(my_dict)
[{'id': 123, 'priority': 1}, {'id': 345, 'priority': 2}, {'id': 234, 'priority': 3}, {'id': 654, 'priority': 4}]
For large datasets this is really slow though, as every single priority change is O(n*log(n)), as it requires a sort.
You should investigate in better data structures, like a heap or a linked list, depending on your exact usage scenario.
Second approach
If we remove the 'priority' member, we can write a much more efficient algorithm:
def move(data, original, target):
data.insert(target, data.pop(original))
# Important: Start priorities at 0, not 1. This makes this a lot easier.
my_dict = [123, 234, 345, 654]
move(my_dict, 3, 0)
print(my_dict)
my_dict = [123, 234, 345, 654]
move(my_dict, 1, 2)
print(my_dict)
[654, 123, 234, 345]
[123, 345, 234, 654]
https://ideone.com/o9UcCb
For a longer discussion about how to move an item inside of a list, read this discussion.
I have an array of objects that looks like this:
[
{
"id": 123,
"timeStamp": "\"2019-07-08T20:36:41.580Z\"",
"data": [1, 2, 3]
},
{
"id": 234,
"timeStamp": "\"2019-07-08T20:37:12.472Z\"",
"data": ["Apples", "Oranges"]
}
]
I want to update the value of a particular property of an object within the array but also want to make sure that I return the result in a new array.
How do I do this without running through some type of a loop e.g. for loop?
Say, I want to update the data property of the second object and add Bananas to it.
If you want the result to be a new array, you'll first have to clone the array. This can be more complicated than you might imagine (depending on how deeply you wish to clone things). One way is to use JSON stringify...
Bear in mind that the JSON trick is effectively doing a loop behind the scenes. Inevitable if you want to copy the array, really.
To find the object by ID use Array.find()
let original = [
{
"id": 123,
"timeStamp": "\"2019-07-08T20:36:41.580Z\"",
"data": [1, 2, 3]
},
{
"id": 234,
"timeStamp": "\"2019-07-08T20:37:12.472Z\"",
"data": ["Apples", "Oranges"]
}
]
let copy = JSON.parse(JSON.stringify(original));
copy.find(obj => obj.id === 234).data.push("Bananas");
console.log(copy);
Something like this would do the trick:
let arr = [
{
"id": 123,
"timeStamp": "\"2019-07-08T20:36:41.580Z\"",
"data": [1, 2, 3]
},
{
"id": 234,
"timeStamp": "\"2019-07-08T20:37:12.472Z\"",
"data": ["Apples", "Oranges"]
}
]
arr[1]['data'] = [...arr[1]['data'], 'Bananas']
console.log(arr)
For your example: you can do something like this: say your array of object is saved in test variable
test[1].data.push("Bananas")
I need a way to check if a Server already exist inside my JSON Array.
Here is an example JSON Array:
[{
"ID": 14,
"PID": 15728,
"Online": 1,
"Servers": "staging,dev,test"
}, {
"ID": 9,
"PID": 6048,
"Online": 1,
"Servers": ""
}, {
"ID": 8,
"PID": 13060,
"Online": 1,
"Servers": "ubuntu,test"
}, {
"ID": 7,
"PID": 15440,
"Online": 1,
"Servers": "main"
}]
I need a JavaScript function to handle this.
Example calls could be:
checkForDupes("staging") -> true
checkForDupes("debian") -> false
checkForDupes("ubuntu") -> true
checkForDupes("test") -> true
You may use some() and includes() methods or arrays and split() method of string:
let data = [
{"ID": 14, "PID": 15728, "Online": 1, "Servers": "staging,dev,test"},
{"ID": 9, "PID": 6048, "Online": 1, "Servers": ""},
{"ID": 8, "PID": 13060, "Online": 1, "Servers": "ubuntu,test"},
{"ID": 7, "PID": 15440, "Online": 1, "Servers": "main"}
];
function checkForDupes(d, s) {
return d.some(o => o["Servers"].split(",").includes(s));
}
console.log(checkForDupes(data, "staging"));
console.log(checkForDupes(data, "debian"));
console.log(checkForDupes(data, "ubuntu"));
console.log(checkForDupes(data, "test"));
Description:
.some() will run the test function against each object and return true if
any one object passes the test.
.split() will create an array from string of "Servers" property delimited by ,
.includes() will check where the passed name exists in array or not returning true or false as appropriate.
Useful Resources:
Array.prototype.some()
Array.prototype.includes()
String.prototype.split()
Arrow Functions
var checkdupe = function(param) {
var count = [];
for(i=0;i<json.length;i++)
{
if(json[i].Servers.split(',').indexOf(param) != -1)
{
count.push(json[i].ID);
}
}
if(count.length>1){
return true;
}
}
you can use that count array to get more detail
indexOf might be the best choice rather than contains or includes, if it comes to a point where speed matters
Trying to see if data in one array matches the data in another. I have an array of objects, like so -
var ProductsList =
[
{"Name": "Product A"; "Rating": "3"},
{"Name": "Product B"; "Rating": "2"},
{"Name": "Product C"; "Rating": "1"},
];
I then want to compare this product list with user selected values, which come in an array that I get based on the values they selected via checkboxes. So if they selected 1, 2, 3 - all products should be shown, if they selected 1 - then only product A is shown.
I tried to use $.grep to do the filtering but I'm running into an issue filtering via array values. Let's hard code the user filer to all values as an example.
userFilterArray.Rating = [1, 2, 3];
function filter(ProductsList, userFilterArray)
filteredList = $.grep(ProductList, function(n) {
return (n.Rating == userFilterArray.Rating);
});
Obviously this doesn't work as I'm comparing n.Rating which is a string to an array but I'm not sure how to compare the string to string in this case.
Would grep be the easiest way to do this? Should I use a combo of .each .each? Maybe neither?
After a bunch of syntax and other fixes, I think this is what you're after:
var ProductsList = [
{"Name": "Product A", "Rating": 3},
{"Name": "Product B", "Rating": 2},
{"Name": "Product C", "Rating": 1}
];
var userFilterArray = [1, 3];
function filter(list, filterArr) {
return $.grep(list, function(obj) {
return $.inArray(obj.Rating, filterArr) !== -1;
});
}
var filteredList = filter(ProductsList, userFilterArray)
console.log( filteredList );
DEMO: http://jsfiddle.net/vK6N9/