Is there a better way to iterate over this JSON data structure? - angularjs

This is the data structure in question:
"EditedArticles" : {
"a3" : {
"versions" : [ {
"moment" : "a3",
"question" : "a3",
"situation" : "a3",
"version" : 1
}, ...
]
}
}
Currently, I am using three for loops to access the properties in EditedArticles.a3.versions
var getArticlesByMoment = function (moment,situation) {
angular.forEach(items, function(article, value) {//items are a1,a2,a3...
angular.forEach(article, function(versions, value) {//versions is the array containing version for each article
var checkfirst=0;
angular.forEach(versions, function(version, value) {//version is the version of an article
checkfirst++;
if (checkfirst == 1 && version.moment == moment && version.situation == situation) {
//do something;
return;
}
})
})
})
}
I want to access the properties inside the versions array for each item (eg. a3) to check if an item has the same moment/situation as a desired one. If there are a lot of items, a1 - a1000, then I think this will take a long running time. There may be many objects in each versions array but I only need to check the first object for a matching moment and situation as the rest of the objects will share the same values for those two properties.
Is there a better/faster way to access these properties? I am using an http GET call to get all the items (eg. a3) in EditedArticles.json
Thank you

You could do this to traverse your json object recursivly:
function traverse(jsonObj) {
if( typeof jsonObj == "object" ) {
$.each(jsonObj, function(k,v) {
// object or array
traverse(v);
});
}
else {
// actual value
}
}

Related

Swift - How to update object in multi-dimensional directory

I want to be able to find and update a custom object in an array of these objects. The challenge is that the custom objects also can be children of the object.
The custom object looks like this:
class CustomObject: NSObject {
var id: String?
var title: String?
var childObjects: [CustomObject]?
}
I would like to be able to create a function that overwrites the custom object with fx a specific ID, like this:
var allCustomObjects: [CustomObject]?
func updateCustomObject(withId id: String, newCustomObject: CustomObject) {
var updatedAllCustomObjects = allCustomObjects
// ...
// find and update the specific custom object with the id
// ...
allCustomObjects = updatedAllCustomObjects
}
I recognize this must be a pretty normal issue regarding multidimensional arrays / directories in both Swift and other languages. Please let me know what normal practice is used for this issue.
As with most things to do with trees, recursion is going to help. You can add an extra parameter that indicates which array of CustomObjects that you are currently going through, and returns a Bool indicating whether the ID is found, for short-circuiting purposes.
#discardableResult
func updateCustomObject(withId id: String, in objectsOrNil: inout [CustomObject]?, newCustomObject: CustomObject) -> Bool {
guard let objects = objectsOrNil else { return false }
if let index = objects.firstIndex(where: { $0.id == id }) {
// base case: if we can find the ID directly in the array passed in
objectsOrNil?[index] = newCustomObject
return true
} else {
// recursive case: we need to do the same thing for the children of
// each of the objects in the array
for obj in objects {
// if an update is successful, we can end the loop there!
if updateCustomObject(withId: id, in: &obj.childObjects, newCustomObject: newCustomObject) {
return true
}
}
return false
// technically I think you can also replace the loop with a call to "contains":
// return objects.contains(where: {
// updateCustomObject(withId: id, in: &$0.childObjects, newCustomObject: newCustomObject)
// })
// but I don't like doing that because updateCustomObject has side effects
}
}
You would call this like this, with the in: parameter being allCustomObjects.
updateCustomObject(withId: "...", in: &allCustomObjects, newCustomObject: ...)

Move/Reorder specific item in Array - SwiftUI

I have a bunch or arrays in a data struct that I am combining into one array and deleting any duplicates. Is it possible to move an item to the top of the array so it is first in the list? I want All to appear at the top of the list but it is currently sitting in the second position because of Agriculture.
Here are some of the arrays in the data struct:
let productData: [ProductModel] = [
ProductModel(application: ["All", "Clean Chemistry", "Food", "Agriculture", "Polymers"]),
ProductModel(application: ["All", "Food", "Agriculture", "Gin", "Polymers"]),
ProductModel(application: ["All", "Metals", "Polymers"]),
]
Here is where I am organising the array and presenting it in a HStack:
struct ProductList: View {
var applicationsArray = Array(Set(productData.flatMap(\.application))).sorted()
var body: some View {
ScrollView(.horizontal){
HStack{
ForEach(applicationsArray, id: \.self) { item in
Button(action: {
// SELECT ITEM
}) {
VStack(alignment: .center){
Image(item)
Text(item)
}
}
}
}
}
}
}
Use the closure provided to sorted(by:) to sort "All" to the front of the list:
var applicationsArray = Set(productData.flatMap(\.application))
.sorted { (a: String, b: String) -> Bool in
a == "All" ? true : b == "All" ? false : a < b
}
Explanation
The closure that you provide to sorted(by:) is called repeatedly by sorted and it takes two elements at a time and decides if the first element should come before the second element. Since you want "All" to appear at the start of the list, then if the closure receives "All" as the first element, it should return true because "All" comes before every other element. If the closure receives "All" as the second element, it returns false because no elements come before "All". Finally, if "All" isn't one of the elements sent to the closure, it just compares to see if the first comes before the second lexicographically using a < b.
First, remove duplicates from your list, then filter out the item(s) you want to show at the top of your list and filter out the rest of your items except the top ones and add them together. Easy right?
var yourList = ["All", "Clean Chemistry", "Food", "Agriculture", "Polymers", "All", "Food", "Agriculture”, "Gin”, "Polymers”, "All”, "Metals”, "Polymers”]
var removeDuplicates = Array(Set(yourList)).sorted()
print(removeDuplicates)
var getAllFromTheList = removeDuplicates.filter(){$0 == "All"}
print(getAllFromTheList) // [“All”]
var removeAllFromTheList = removeDuplicates.filter(){$0 != "All"}
print(removeAllFromTheList) // [“Agriculture”, “Clean Chemistry”, “Food”, “Gin”, “Metals”, “Polymers”]
let newList = getAllFromTheList + removeAllFromTheList
print(newList) // [“All”, “Agriculture”, “Clean Chemistry”, “Food”, “Gin”, “Metals”, “Polymers”]

Typescript: Strongly type incoming array with variable types

I have a JSON array which can contain either of two types defined by IPerson and ICompany.
[
{ "Name" : "Bob", "Age" : 50, "Address": "New Jersey"},
{ "Name" : "ABC Inc", "Founded" : 1970, "CEO": "Alice" }
]
This data is received from an endpoint. I want to map this data exactly in same way in my client application in Typescript. How should I define my model in this case.
I know we can define same interfaces in TypeScript but is it possible to have an array that holds either of two objects defined by IPerson and ICompany and know the type of each item while iterating the array?
You can have an Array<IPerson | ICompany>. For iterating, you can do something like this
function iterateMyArray(array: Array<IPerson | ICompany>) {
array.forEach(item => {
if ('Age' in item) {
// item is an person
console.log(item.Address);
} else {
// item is a company
}
})
}

Get index of array item if item of array equals name

I have an array of items like this:
{
"dateAdded" : "2016-02-09 12:41:37",
"customValue" : "5",
"name" : "highestHeight"
},
{
"dateAdded" : "2016-02-09 12:41:37",
"customValue" : "46.91",
"name" : "highestWeight"
},
{
"dateAdded" : "2016-02-09 12:41:37",
"customValue" : "14972.02",
"name" : "highestScore"
},
I would like to get the items associated with the item that has the name = highestScore but not sure how or even what I should be searching for to find an example.
How about starting with the documentation on Array, which will show that it implements the CollectionType protocol, which has a filter function:
myArray.filter({ $0.name == "highestScore" })
That assumes it is an array of objects/types, and not an array of Dictionary instances. If that was the case, then you would use:
myArray.filter({ $0["name"] == "highestScore" })
You can look at functional filtering here: http://www.raywenderlich.com/82599/swift-functional-programming-tutorial
Do something like:
highscoreArray= yourArray.filter { (dictionary) in dictionary["name"]! == "highestScore" }
Haven't tested it but it should be along of the lines of that.

MongoDB $elemMatch in Meteor

I have a small question about $elemMatch. This is a document in MongoDB:
{
_id:'asdf1234',
latest: '2.0.0',
foo : [{
v : '1.0.0',
text : "Hello"
},{
v: '2.0.0',
text : "Hello v2.0.0"
}]
}
I want to return only foo with v same as in latest field. For now I can do something like this:
var a = function(id, version) {
//id = 'asdf1234'
//version = '2.0.0'
return MyCollection.findOne({_id:id}, {fields:{foo:{$elemMatch:{v:version}}});
}
and I will get foo array only with object with v:'2.0.0'. But now i want to get latest object in array, so parameter version will be 'latest' and function will look like this:
var a = function(id, version) {
//id = 'asdf1234'
//version = 'latest'
if(version != 'latest') {
return MyCollection.findOne({_id:id}, {fields:{foo:{$elemMatch:{v:version}}});
} else {
var doc = MyCollection.findOne({_id:id});
//Some code to get object where v == doc.latest
}
}
And now question - can I get element from foo Array only with one query, something like this:
MyCollection.findOne({_id:id}, {fields:{foo:{$elemMatch:{v:'$latest? or fields.latest?'}}});
I don't want to iterate through array to get latest element. Of course, if there is no chance to get it like this, I will write finding code :)
Thanks for any answers!
Mongo find will give you the complete document with all entries in your array. It's not possible to select one of the foo array's items with a Mongo query. You need to find the correct subdocument once you have the array.
Fortunately, it's quite simple:
_.find(doc.foo, function(item) {return item.v === doc.latest});

Resources