How To Map An Array [Swift] - arrays

I have an array named bonusCardsTest of type [BonusCard] that is conformed to Identifiable that has an id and an url property of type String.
var bonusCardsTest: [BonusCard] = []
struct BonusCard: Identifiable {
var id = UUID().uuidString
var url: String
}
I also have an array named getBonusURLsArray of type [String] that contains urls.
What I want is to assign each element of getBonusURLsArray to the url property of bonusCardsTest.
For example, if getBonusURLsArray has two elements - "https://test1.com", "https://test2.com", I want the BonusCard array to look like this:
var bonusCardsTest: [BonusCard] = [
BonusCard(url: "https:test1.com"),
BonusCard(url: "https:test2.com"),
]
How do I do that?

As Larme says, you could map your array of URLs to BonusCards:
let bonusCards = getBonusURLsArray.map { BonusCard(url: $0) }

Related

Chaining filter and map array by dictionary values in Swift

how can I use this type of chaining
let numbers = [20,17,35,4,12]
let evenSquares = numbers.filter{$0 % 2 == 0}.map{$0 * $0}
in such usecase
I have array of objects, I want to filter it by keys of external dictionary and then assign to those filtered objects value of dictionary where object id = dictionary key and then sort result object by dictionary value
here is code I have now:
let scoreDict: [String: Double]
var objects: [Object]
var filteredObjects = objects.filter { scoreDict.keys.contains.contains($0.id.uuidString.lowercased()) }
// .. and what next?
var scoresAssigned = filteredObjects.map { $0.score = scoreDict[$0.id.uuidString.lowercased()] } // This do not compile ""Cannot assign to property: '$0' is immutable"
Assuming Object is a struct, based on the error message...
This just shows that higher-order functions shouldn't be used everywhere. map transforms each element in a sequence into something else. So instead of assigning score, you need to return a new Object with its score changed.
var scoresAssigned = filteredObjects.map { $0.withScore(scoreDict[$0.id.uuidString.lowercased()]) }
withScore will look something like:
func withScore(_ score: Int) -> Object {
var copy = self
copy.score = score
return copy
}
But, if you just want to assign the score a new value, I recommend a simple for loop.
for i in 0..<filteredObjects.count {
filteredObjects[i].score = scoreDict[$0.id.uuidString.lowercased()]
}
Also note that you only need to access the dictionary once. If it's nil, the key doesn't exist.
var filteredObjects = [Object]()
for i in 0..<objects.count {
if let score = scoreDict[$0.id.uuidString.lowercased()] {
objects[i].score = score
filteredObjects.append(objects[i])
}
}

Create an object array from another object array and reconstruct the original object array later using map

Consider the following classes
class Category {
var tag: String?
var itemList: [Item]?
}
class Item {
var id: Int?
var type: String?
var itemDetails: ItemDetails?
}
class ItemDetails {
var description: String?
var name: String?
var price: Float?
}
Given an array of Category objects.
var categoryList: [Category]
I want to create a new object array by extracting only the name in ItemDetails(inorder to apply a filter) and an id inorder to reconstruct back array of Category objects.
Hence, I have to reconstruct the array of Category objects
from new object array.
How to do both extraction and reconstruction using the map feature?
Below are the examples of other data sources:
Datasource 1 :
var categoryList: [Category], where name need to be extracted
Datasource 2 :
var searchList = [SearchItem], where title to be extracted.
Class SearchItem {
var id: Int?
var details: SearchItemDetails?
var type: String?
}
Class SearchItemDetails {
var description: String?
var title: String?
}
DataSource 3
var products: [Products], where title to be extracted.
Class Products {
var id: Int?
var details: ProductDetails?
var type: String?
}
class ProductDetails {
var description: String?
var title: String?
}
To get an array of just the names, you do the map like you mentioned:
let categories: [Category] = ... // this already exists
let itemNames = categories.map { $0.itemList?.map({ $0.itemDetails?.name }) }
But this will preserve optionals. If you don't want optionals, then use compactMap instead.
Reconstructing, however, doesn't really make any sense. Are you using the ID to hit a database or network service? That's the only possible way you'd be able to reconstruct the original array of Categorys. Why not just hold onto the original array?

Swift: How to define a fixed array of flexible String array

I already have several arrays for strings. I want to add them to a list of arrays, so I can use a predefined (enum) index. The individual arrays are already in place, I only need to access them via index (fixed with enum or within a loop with index from enum type). So there should be no copy of the strings within the array, only a reference to the array itself.
I already have this in mind:
enum TypeOfArray: Int {
case Src = 0, Dest, SrcCache, DstCache, N
}
var srcFolders : [String] = []
var dstFolders : [String] = []
var srcFoldersCache : [String] = []
var dstFoldersCache : [String] = []
var allFolders: [[String]] = []
Then I want to initilaze the main array by assigning each of the individual arrays. But this is rejected by the compiler: ("Cannot subscript a value of type '[[String]]' with an index of type 'TypeArray'")
allFolders[TypeOfArray.Src] = srcFolders
I don't know if this "typesave" index is even possible.
Can I use a fixed index range 0..N when defining for optimizing memory or speed?
Any ideas?
A dictionary would be a good solution for this:
var dict = [TypeOfArray:[String]]()
dict[TypeOfArray.Src] = srcFolders
Singleton
If you want to share the content of your arrays, an you want the updates to be reflected in your code, you can use a Singleton
final class ImageNameManager {
static let sharedInstance = ImageNameManager()
var srcFolders: [String]
var dstFolders: [String]
var srcFoldersCache: [String]
var dstFoldersCache: [String]
private init() {
// populate: srcFolders, dstFolders, srcFoldersCache, dstFoldersCache
srcFolders = []
dstFolders = []
srcFoldersCache = []
dstFoldersCache = []
}
enum ImageType: Int {
case Src = 0, Dest, SrcCache, DstCache
}
func imageNames(imageType: ImageType) -> [String] {
switch imageType {
case .Src: return srcFolders
case .Dest: return dstFolders
case .SrcCache: return srcFoldersCache
case .DstCache: return dstFoldersCache
}
}
}
Usage
Now you can populate one of your array
ImageNameManager.sharedInstance.dstFolders.append("Hello")
and receives the new data in another section of your code
let dstFolders = ImageNameManager.sharedInstance.imageNames(.Dest)
// ["Hello"]
Update
In order to share the same array across your app you cal also use this code
final class ImageNameManager {
static let sharedInstance = ImageNameManager()
var srcFolders: [String] = []
var dstFolders: [String] = []
var srcFoldersCache: [String] = []
var dstFoldersCache: [String] = []
}
Now alway reference it the array with this code ImageNameManager.sharedInstance.dstFolders, look
ImageNameManager.sharedInstance.dstFolders.append("Hello")
ImageNameManager.sharedInstance.dstFolders.append("World")
ImageNameManager.sharedInstance.dstFolders // ["Hello", "World"]

Reduce array to set in Swift

I am trying to reduce an array of objects to a set in Swift and this is my code:
objects.reduce(Set<String>()) { $0.insert($1.URL) }
However, I get an error:
Type of expression is ambiguous without more context.
I do not understand what the problem is, since the type of URL is definitely String. Any ideas?
You don't have to reduce an array to get it into a set; just create the set with an array: let objectSet = Set(objects.map { $0.URL }).
With Swift 5.1, you can use one of the three following examples in order to solve your problem.
#1. Using Array's map(_:) method and Set's init(_:) initializer
In the simplest case, you can map you initial array to an array of urls (String) then create a set from that array. The Playground below code shows how to do it:
struct MyObject {
let url: String
}
let objectArray = [
MyObject(url: "mozilla.org"),
MyObject(url: "gnu.org"),
MyObject(url: "git-scm.com")
]
let urlArray = objectArray.map({ $0.url })
let urlSet = Set(urlArray)
dump(urlSet)
// ▿ 3 members
// - "git-scm.com"
// - "mozilla.org"
// - "gnu.org"
#2. Using Array's reduce(into:_:) method
struct MyObject {
let url: String
}
let objectArray = [
MyObject(url: "mozilla.org"),
MyObject(url: "gnu.org"),
MyObject(url: "git-scm.com")
]
let urlSet = objectArray.reduce(into: Set<String>(), { (urls, object) in
urls.insert(object.url)
})
dump(urlSet)
// ▿ 3 members
// - "git-scm.com"
// - "mozilla.org"
// - "gnu.org"
As an alternative, you can use Array's reduce(_:_:) method:
struct MyObject {
let url: String
}
let objectArray = [
MyObject(url: "mozilla.org"),
MyObject(url: "gnu.org"),
MyObject(url: "git-scm.com")
]
let urlSet = objectArray.reduce(Set<String>(), { (partialSet, object) in
var urls = partialSet
urls.insert(object.url)
return urls
})
dump(urlSet)
// ▿ 3 members
// - "git-scm.com"
// - "mozilla.org"
// - "gnu.org"
#3. Using an Array extension
If necessary, you can create a mapToSet method for Array that takes a transform closure parameter and returns a Set. The Playground below code shows how to use it:
extension Array {
func mapToSet<T: Hashable>(_ transform: (Element) -> T) -> Set<T> {
var result = Set<T>()
for item in self {
result.insert(transform(item))
}
return result
}
}
struct MyObject {
let url: String
}
let objectArray = [
MyObject(url: "mozilla.org"),
MyObject(url: "gnu.org"),
MyObject(url: "git-scm.com")
]
let urlSet = objectArray.mapToSet({ $0.url })
dump(urlSet)
// ▿ 3 members
// - "git-scm.com"
// - "mozilla.org"
// - "gnu.org"
reduce() method expects a closure that returns a combined value, while insert() methods of Set value does not return anything but instead it inserts a new element into the existing set.
In order to make it work you would need to do something like:
objects.reduce(Set<String>()) {
$0.union(CollectionOfOne($1.URL))
}
But the above is a bit of an unnecessary complication. If you have a big array, that would mean quite a number of ever-growing sets to be created while Swift goes over all the elements from objects. Better follow the advice from #NRitH and use map() as that would make a resulting set in one go.
Swift 1.0-2.x ONLY:
If URL on your object is a strongly-typed String, you can create a new Set<String> object and use unionInPlace on the set with the mapped array:
var mySet = Set<String>()
mySet.unionInPlace(objects.map { $0.URL as String })

How to save an array to a Realm Object

I am new to using Realm. Is there an easy way to save an array to a realm object? I am receiving my data from a JSON REST call:
class SomeClass: RLMObject {
dynamic var id = 0
dynamic var name = ""
dynamic var array: NSArray
func checkForUpdates() {
// Download JSON data here... The results have an array inside of them.
SomeClass.createOrUpdateInDefaultRealmWithObject(SomeNSDictionary)
}
override class func primaryKey() -> String! {
return "id"
}
}
Is it possible to save the array in the JSON results in Realm?
Thanks.
Realm has a special RLMArray type, which allows storing a collection of RLMObject's tied to a parent RLMObject. For example, say you had the following JSON:
{
"name": "John Doe",
"aliases": [
{"alias": "John"},
{"alias": "JD"}
]
}
You could model this with the following classes:
class Alias: RLMObject {
dynamic var alias = ""
}
class Person: RLMObject {
dynamic var name = ""
dynamic var aliases = RLMArray(objectClassName: "Alias")
}
So you could simply create a Person object with the following API call:
Person.createInRealm(realm, withObject: jsonObject)
You can learn more about how RLMArrays work from Realm's reference documentation: http://realm.io/docs/cocoa/0.80.0/api/Classes/RLMArray.html

Resources