Get formatted list of values from array in swift - arrays

im making sort of food delivery app with some backend functional, and now im struggling with getting elements of array as formatted order strings
guard
let defaults = UserDefaults.standard.data(forKey: "itemlist"),
let savedItems = try? JSONDecoder().decode([Order].self, from: defaults)
else {
return
}
let dictionary = savedItems.compactMap({ ($0.name!, $0.price!) })
let dishNames = dict.joined(separator: ",") //error
let order = "Заказ: \(dictionary)"
print(order)
result im getting:
[("Пепперони", "45см/500р."), ("Деревенская", "45см/520р.")]
what i want:
Пепперони 45см/500р. Деревенская 45см/520р.
i could do that easily in php, but im not finding analogues in swift, might anyone help me?

Related

Value of type 'Article' has no subscripts

So I know there are many other similar questions about this type of problem, but my fried brain cells genuinely cannot, for the life of me, figure out how to solve the following error: "Value of type 'Article' has no subscripts". I tried applying a lot of other solutions from other Stack Overflow posts, but the issue still persists.
Brief overview about my project: I'm trying to use a news API for some intended application. However, there are a lot of duplicate news articles within my array -- that I'm trying to remove.
So here is my API Call, works like a charm:
let topic_endpoint = "blah blah endpoint + secret api_key"
guard let url = URL(string: topic_endpoint) else {
print("Error creating url object")
return
}
let request = URLRequest(url: url)
URLSession.shared.dataTask(with: request){ data, _, error in
if error != nil {
print((error?.localizedDescription)!)
return
}
if let data = data {
let response = try! JSON(data: data)
for index in response["articles"]{
let id = index.1["publishedAt"].stringValue
let title = index.1["title"].stringValue
let description = index.1["description"].stringValue
let image = index.1["urlToImage"].stringValue
let url = index.1["url"].stringValue
DispatchQueue.main.async {
//print(response)
if self.getSentimentFromBuildInAPI(text: title) == 1{
self.articles.append(Article(id: id, title: title, description: description, image: image, url: url))
}
}
}
}
}.resume()
And here is my removeDuplications function:
I first iterate throughout the entire array of type Article, and then add the title into a new array called 'usedNames'. At every step, I check to see if any other title is already used and added, and if it does I skip over that value to my array again. Hopefully, I explained this well, please let me know if I need to change anything.
func removeDuplications(){
//haven't used title yet, this is was just something I tried looking off another stackoverflow post.
guard let title = self.articles["title"] as? [[String: Any]] else{
print("error: dictionary type not recognized")
}
for index in self.articles{
if(!self.usedNames.contains(index["title"])){ //<----------this is where I get my error: 'Value of type 'Article' has no subscripts'
//Tried reappending the new titled articles (below) into my Published dictionary/array, is also showing the same issue as above
//self.articles.append(Article(id: index["id"], title: index["title"], description: index["description"], image: index["image"], url: index["url"]))
self.usedNames.append("title")
}
}
}
Thanks so much for helping me with this, really appreciate it:)
It's likely because in your
for index in self.articles
index (which is of type Article) can not be used as a dictionary, which is what you are doing when you do index["title"]
Instead, you have to do:
index.title
instead of
index["title"]

How do I fill an array of data with CoreData data?

I am learning to use SwiftUI with Core Data.
I am trying to fill a Line Chart with saved weight data like below:
LineView(data: [0, 32, 445, 56, 99])
I’ve gotten as far as this but im getting an error on the "var locations = ..." line saying "Type of expression is ambiguous without more context"
var fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserWeight")
var locations = mocW.executeFetchRequest(fetchRequest, error: nil) as [UserWeight]
for weight in weights {
print(weights.userWeight)
}
Any help on this and how i would populate the line chart with this data would be greatly appreciated!
For SwiftUI, I suspect that you are attempting to achieve the following...
struct YourView: View {
#FetchRequest(entity: UserWeight.entity(),
sortDescriptors: []
) var weights: FetchedResults<UserWeight>
var body: some View {
ForEach(weights) { weight in
Text(weight.userWeight)
}
}
}
Core Data entities confirm to the Identifiable protocol, so you'e able to drop the id: parameter in the ForEach structure...
ForEach(weights) { weight in
Otherwise you'd need to use...
ForEach(weights, id: \.self) { weight in
Note: As an aside, it would help us if you could provide more detail in your questions in the future. The more information you provide, the easier it is for the community to understand your issue and provide a suitable response. Remember that your question and our answers may not only help you, but also help others in the future as they visit the site looking for answers to their own problems.
How do I ask a good question?
if let appDelegate =
UIApplication.shared.delegate as? AppDelegate {
let managedObjectContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Memory>(entityName: "Memory")
let sortDescriptor = NSSortDescriptor(key: "rating", ascending: false)
var predicate = NSPredicate(format: "mediaType == %#", "image")
fetchRequest.predicate = predicate
fetchRequest.sortDescriptors = [sortDescriptor]
do {
result = try managedObjectContext.fetch(fetchRequest)
} catch {
}
}
"result" is an array of, in my case, Memory objects which are instances of NSManagedObject. To access properties and populate views I do this:
for memory in result {
let value = memory.entityPropertyName
}
I think this should be enough to get your started, let me know if you have more questions.
If UserWeight is a subclass of NSManagedObject, you should declare your fetch request as
var fetchRequest = NSFetchRequest<UserWeight>(entityName: "UserWeight")
Or else as
let fetchRequest: NSFetchRequest<UserWeight> = UserWeight.fetchRequest()
Then you can use the fetch like this, and the type of locations will be Array<UserWeight>.
let locations = try context.fetch(fetchRequest)
I'm not sure where executeFetchRequest(fetchRequest, error: nil) comes from-- it's not a function defined by NSManagedObjectContext in Swift. It resembles the Objective-C version of the function, but in Swift it's different.

Search Multiple Words (or Characters) in String Array (swift)

I am developing an application for words.
My problem resembles the problem: this
But, I want to do the search in the string array.
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = ["I","N"]
// myArr.contains(findChrs) //so error
I want to: return 3 or "BERLIN","ISTANBUL" and "WIEN" (Contains "I" and "N")
I tried it, but it's too long...(I look individually. Too many words.):
for i in 0...myArr.count - 1 {
let success = !findChrs.contains(where: { !myArr[i].contains($0) })
if success {
print(myArr[i])
}
}
Is there an easier way? Thank you so much.
There's a swifty way to solve your problem
I started with using just one filter on the myArr array using hardcoded search terms
let filteredStrings : [String] = myArr.filter({
return $0.contains("I") && $0.contains("N")
})
but thats going to help only if your findChars are always going to be I and N only.
Later I realized how to do it without hardcoding the find char characters:
ANSWER 1
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = ["I","N"]
let filteredStrings : [String] = myArr.filter({ (aString) in
let hasChars = findChrs.filter({(bString) in
return aString.contains(bString)
})
print(hasChars)
return hasChars.count == findChrs.count
})
print(filteredStrings)
Instead of using $0, I think in the second chunk of code, its easier to understand whats happening with aString and bString.
Do check the code in a playground and see how this code works. If you haven't used the higher order functions, it can be a little daunting to understand filters without a playground and the print statements.
Update:
Was just thinking about this problem and I gave this alternate approach a try, using sets, map and filter. It is super swifty, and can be difficult to read/understand:
ANSWER 2, concise
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = ["I","N"]
let finderSet:Set<String> = Set(findChrs)
let filteredArray = myArr.filter {
return Set($0.characters.map({String($0)})).intersection(finderSet).count == findChrs.count
}
For the sake of readability and ease of understanding, here's what is happening:
Answer 2, verbose
let filteredArray = myArr.filter { (aString) -> Bool in
//for each string in myArr, convert it into an array of string chars
let stringArray = aString.characters.map({aCharacter in
String(aCharacter)
})
//convert string array into a set
let aSet = Set(stringArray)
// find the intersection (common elemnts from aSet and finderSet)
let intersect = aSet.intersection(finderSet)
//return true if aString has all of findChrs elements
return intersect.count == findChrs.count
}
Both Answer 2 'concise' and 'verbose' will give you the same results.
Based on some simple code execution time check, it looks like Answer 1 is ~3x faster than Answer 2. So, Answer 1 is still a better choice and probably easier to understand.
Hope this helps anyone reading the answer understand filter and map!
You could also use a set for the filter provided you're not looking for patterns that contain repeated letters:
let myArr: [String] = ["BERLIN","ISTANBUL","TOKYO","NEWYORK","PRAGUE","WIEN"]
let findChrs = Set<Character>(["I","N"]) // let findChrs = Set("IN")
let matchingCities = myArr.filter{ findChrs.isSubset(of:$0) }

How to save response.result.value from Alamofire in local array swift 3

Alamofire.request(NEWS_FEED_URL).responseJSON { response in
guard let newsResponse = response.result.value else{
print("Error: \(response.result.error)")
return
}
print("JSON: \(newsResponse)")
let localArray:Array = [newsResponse]
print("Local Array:", localArray)
}
I am using alamofire to fetch data from server and trying to write parser on the response data. When I fetch response.result.value from alamofire and print it is working fine. But as soon as I put response.result.value in my local array it gives
[<__NSArrayI 0x6080000bcf80>(
{
category = World;
})]
and so on as result (Console). Also I am unable to convert response value of type 'Any' to 'Array'. Please help me how to add response.result.value in local array of type 'Array'. Can someone explain something about type casting on alamofire in brief?
You need to simply cast the result of response.result.value to Array of Dictionary.
guard let newsResponse = response.result.value as? [[String:String]] else{
print("Error: \(response.result.error)")
return
}
print("JSON: \(newsResponse)")
let localArray = newsResponse
//Access the localArray
print("Local Array:", localArray)
//Now to get the desired value from dictionary try like this way.
let dic = localArray[0]
let title = dic["title"] ?? "Default Title"
let link = dic["link"] as? "Default link"
//... get other value same way.
Note : Your response is already an Array so don't make array from it by adding it inside another array.
There is problem in responseJOSN result because result may not correct JSON format to correct use [[String:Any]] for formating JSON
Alamofire.request(NEWS_FEED_URL).responseJSON { response in
guard let newsResponse = response.result.value as? [[String:Any]] else{
print("Error: \(response.result.error)")
return
}
print("JSON: \(newsResponse)")
let firstRow = newResponse[0]
let categoryValue = firstRow["category"] ?? "Default Category"
}
If you are using Decodable technique you can save the DATA from response in user defaults. User defaults allows us to save the DATA. When you need it you can just use JSON decoder to decode the JSON Data.

Convert Parse.com json array into Array with swift

Can someone please help me with this. I saved my data into Parse.com into column with type array (example: ["11:30","12:45,"13:02"], just some list of some times as string). I have tried to get this data with swift:
var take: NSMutableArray!
var query = PFQuery(className: "test")
query.getObjectInBackgroundWithId("QZ6Y8Oljc5"){
(testData: PFObject!, error: NSError!) -> Void in
if (error == nil){
take = testData["workday"]
println(take)
}
else{
println(error)
}
}
the problem is that i get only json array type:
(
"11:30",
"12:45,
"13:02"
)
How can I convert it into NSArray so it could be like:
var myArray = ["11:30","12:45,"13:02"]
Thank you for any suggestions because I tried every method I found here, but without any results.
The problem with JSON data is that it is it's own array that has to be sifted and groomed. normally people would end up using huge nested IF statements which ends up looking messy. Luckily, someone created a code that sifts through JSON data and gives you back usable types (Int, Arrays, Strings) by use of a massive switch table.
https://github.com/SwiftyJSON/SwiftyJSON
Look it up, it should help. Once you have it implemented you can call it by typing..
let json = JSON(Data : JSONData)
then to sift through, you use substrings.. (depending on the data, you match it with a string or int)
let firstIndex = json["workday"]
//Int
let firstIndexOfWorkDay = json["workday"][0]
//String
let firstIndexOfWorkDay = json["workday"]["time"]
and so on... however, you will need to cast it once you singled out the data
let firstIndexOfWorkDay = json["workday"][0].valueOfFloat
//printing it would give 11:30
although personally I use ".description" .. since sometimes when I sift through all the array, its a mix of types.
let firstIndexOfWorkDay = json["workday"][0].description
println(firstIndexOfWorkDay)
//would literally give "11:30" including the quotation marks
then I use string methods to trim the quotations then cast it to whatever type I need. But it's up to your creativity once you figure out how it works

Resources