RealmSwift obtain each T object - ios

I have list of objects T and I want to calculate their sum (T objects)
var objects: Observable<List<T>>
T object has a method which return Int value.
The main idea to get each object and prepare array of values (flatMap function). The next step will be reduce func with Int values.
let sum = values.reduce(0) { $0 + $1 }
Q: How to get each T object?

Have a look at the solution below which is trying to demonstrate what you are trying to do, you might need a protocol for type T that has int property like the example below. You can try it with playground.
protocol Countable {
var value: Int { get }
init(value: Int)
}
class User: Countable {
var value: Int = 0
required convenience init(value: Int) {
self.init()
self.value = value
}
}
class UserGroup<T: Countable> {
func calculateTotal() {
let users: [T] = [T(value: 2), T(value: 21)]
let total = users.flatMap { ($0 as Countable).value }.reduce(0) { $0 + $1 }
print("total", total)
}
}
let userGroup = UserGroup<User>()
userGroup.calculateTotal()

Related

how to create anonymous list in swift, such as Kotlin

While i were changing kotlin code to swift code. I had a problem with create abstract immutable list.
private interface A{
val Id : Int
val anotherValue : Int
}
private val anotherList : ArrayList<A>
override val idList: List<Int>
get() = object : AbstractList<Int>() {
override val size: Int
get() = anotherList.size
override fun get(index: Int): Int {
return anotherList[index].Id
}
}
This code is create 'AbstractList' on call the 'idList' property. I intended not to take up any additional capacity except for the created instance's own.
I tried to migrating code as follows at Swift:
override var idList: [Int]{
return self.anotherList.map{
$0.Id
}
}
However, this code takes up more memory, such as List Copy. How can i do?
You could use a lazy map:
let idList: LazyMapSequence<[A], Int> {
self.anotherList.lazy.map(\.id)
}
I am pretty sure lazy gives you a lazy "view" of the array. And since this is a lazy sequence, the ids won't be computed until you need them. Also, because arrays are random access, if you need, say, the third id, the first and second id won't be computed.
Alternatively, and I think this is better, write your own ArrayKeyPathView collection:
struct ArrayKeyPathView<WrappedElement, KeyPathType> : RandomAccessCollection {
subscript(position: Int) -> Element {
get {
wrapped[position][keyPath: keyPath]
}
}
var startIndex: Int {
wrapped.startIndex
}
var endIndex: Int {
wrapped.endIndex
}
var indices: Range<Int> {
wrapped.indices
}
typealias Index = Int
typealias SubSequence = ArrayKeyPathView
typealias Element = KeyPathType
typealias Indices = Range<Int>
private let wrapped: [WrappedElement]
private let keyPath: KeyPath<WrappedElement, KeyPathType>
init(_ array: [WrappedElement], keyPath: KeyPath<WrappedElement, KeyPathType>) {
self.wrapped = array
self.keyPath = keyPath
}
}
Usage:
let idList: ArrayKeyPathView<A, Int> {
ArrayKeyPathView(self.anotherList, keyPath: \.id)
}
Since swift arrays are copy-on-write, just passing it to ArrayKeyPathView doesn't create a copy.

How To constraint parameter of generic type in function, to sibling parameter

To understand the origin of the question, let's start with some code:
protocol MyProtocol {
var val1: Int { get set }
}
struct StructA: MyProtocol {
var val1: Int
var structAVal: Int
}
struct StructB: MyProtocol {
var val1: Int
var structBVal: Int
var thirdProperty: Int
}
And then I have a struct with a heterogeneous array of type MyProtocol:
struct Values {
var arr: [MyProtocol] = [StructA(val1: 0, structAVal: 0), StructB(val1: 0, structBVal: 0)]
}
if I was to change one of the values with a method in Values such as:
struct Values {
var arr: [MyProtocol] = [StructA(val1: 0, structAVal: 0), StructB(val1: 0, structBVal: 0)]
mutating func set<T: MyProtocol>(at index: Int, _ newValue: T) {
arr[index] = newValue
}
}
That would be smooth.
The problem which I am facing is, say I wanted to change var thirdProperty: Int in the structB item in var arr: [MyProtocol], I would not be able to do so which my mutating func set<T: MyProtocol>(at index: Int, _ newValue: T), since It only knows of MyProtocol types.
So my 2 cents to resolve this matter was using a closure something like this:
mutating func set<T: MyProtocol>(at index: Int, closure: (T?) -> (T)) {
arr[index] = closure(arr[index] as? T)
}
The problem with this is that every time I invoke this method, I would first need to downcast the parameter (from MyProtocol to StructB). which seems more of a workaround which could invite unwanted behaviours along the road.
So I started thinking maybe there is a way to constraint the generic parameter to a sibling parameter something like this (pseudo code):
mutating func set<T: MyProtocol>(type: MyProtocol.Type, at index: Int, closure: (T?) -> (T)) where T == type {
arr[index] = closure(arr[index] as? T)
}
Which as you guessed, does not compile.
Any thought on how to approach this matter in a better manner. T.I.A
Use T.Type instead of MyProtocol.Type in the set(type:at:closure:) method.
struct Values {
var arr: [MyProtocol] = [StructA(val1: 0, structAVal: 0), StructB(val1: 0, structBVal: 0, thirdProperty: 0)]
mutating func set<T: MyProtocol>(type: T.Type, at index: Int, closure: ((T?) -> (T?))) {
if let value = closure(arr[index] as? T) {
arr[index] = value
}
}
}
Example:
var v = Values()
v.set(type: StructB.self, at: 1) {
var value = $0
value?.thirdProperty = 20
return value
}
Do let me know if this is the right understanding of your requirement.
PGDev's solution gets to the heart of the question, but IMO the following is a bit easier to use:
enum Error: Swift.Error { case unexpectedType }
mutating func set<T: MyProtocol>(type: T.Type = T.self, at index: Int,
applying: ((inout T) throws -> Void)) throws {
guard var value = arr[index] as? T else { throw Error.unexpectedType }
try applying(&value)
arr[index] = value
}
...
var v = Values()
try v.set(type: StructB.self, at: 1) {
$0.thirdProperty = 20
}
The = T.self syntax allows this to be simplified a little when the type is known:
func updateThirdProperty(v: inout StructB) {
v.thirdProperty = 20
}
try v.set(at: 1, applying: updateThirdProperty)
Another approach that is more flexible, but slightly harder on the caller, would be a closure that returns MyProtocol, so the updating function can modify the type. I'd only add this if it were actually useful in your program:
mutating func set<T: MyProtocol>(type: T.Type = T.self, at index: Int,
applying: ((T) throws -> MyProtocol)) throws {
guard let value = arr[index] as? T else { throw Error.unexpectedType }
arr[index] = try applying(value)
}
...
try v.set(type: StructB.self, at: 1) {
var value = $0
value.thirdProperty = 20
return value // This could return a StructA, or any other MyProtocol
}
(Which is very close to PGDev's example, but doesn't require Optionals.)

Removing Duplicates From Array of Custom Objects Swift

I have a custom class defined as follows :
class DisplayMessage : NSObject {
var id : String?
var partner_image : UIImage?
var partner_name : String?
var last_message : String?
var date : NSDate?
}
Now I have an array myChats = [DisplayMessage]?. The id field is unique for each DisplayMessage object. I need to check my array and remove all duplicates from it, essentially ensure that all objects in the array have a unique id. I have seen some solutions using NSMutableArray and Equatable however I'm not sure how to adapt them here; I also know of Array(Set(myChats)) however that doesn't seem to work for an array of custom objects.
Here is an Array extension to return the unique list of objects based on a given key:
extension Array {
func unique<T:Hashable>(map: ((Element) -> (T))) -> [Element] {
var set = Set<T>() //the unique list kept in a Set for fast retrieval
var arrayOrdered = [Element]() //keeping the unique list of elements but ordered
for value in self {
if !set.contains(map(value)) {
set.insert(map(value))
arrayOrdered.append(value)
}
}
return arrayOrdered
}
}
for your example do:
let uniqueMessages = messages.unique{$0.id ?? ""}
You can do it with a set of strings, like this:
var seen = Set<String>()
var unique = [DisplayMessage]
for message in messagesWithDuplicates {
if !seen.contains(message.id!) {
unique.append(message)
seen.insert(message.id!)
}
}
The idea is to keep a set of all IDs that we've seen so far, go through all items in a loop, and add ones the IDs of which we have not seen.
Here is an Array extension to return the unique list of objects based on a keyPath:
extension Array {
func uniques<T: Hashable>(by keyPath: KeyPath<Element, T>) -> [Element] {
return reduce([]) { result, element in
let alreadyExists = (result.contains(where: { $0[keyPath: keyPath] == element[keyPath: keyPath] }))
return alreadyExists ? result : result + [element]
}
}
}
Usage:
myChats.uniques(by: \.id)
Create a free duplicate version of an Array, using equality comparisons based on a given key
public extension Sequence {
public func uniq<Id: Hashable >(by getIdentifier: (Iterator.Element) -> Id) -> [Iterator.Element] {
var ids = Set<Id>()
return self.reduce([]) { uniqueElements, element in
if ids.insert(getIdentifier(element)).inserted {
return uniqueElements + CollectionOfOne(element)
}
return uniqueElements
}
}
public func uniq<Id: Hashable >(by keyPath: KeyPath<Iterator.Element, Id>) -> [Iterator.Element] {
return self.uniq(by: { $0[keyPath: keyPath] })
}
}
public extension Sequence where Iterator.Element: Hashable {
var uniq: [Iterator.Element] {
return self.uniq(by: { (element) -> Iterator.Element in
return element
})
}
}
Usage
let numbers = [1,2,3,4,5,6,7,1,1,1,]
let cars = [Car(id:1), Car(id:1), Car(id:2)]
numbers.uniq
cars.uniq(by: { $0.id})
cars.uniq(by: \Car.id)
cars.uniq(by: \.id)

Sort Two Arrays of Different Types into One

I have two arrays, they are of two different objects, and both contain an ID field. What I need to do is display them in order in a table view controller. They share the same basic info, Size and ID, and those are the only pieces of data displayed, in addition to the type of object it is. When the user selects a cell then it moves to a new view that displays the finer details of the object.
Right now, I have two sections in the table, one for TypeA, and the other for TypeB. They sort through all of the items in their respective list, but are out of order for when the item was made. So it looks like:
TypeA
ID 1
ID 2
ID 5
ID 6
TypeB
ID 3
ID 4
ID 7
What I need is for it to sort them all into 1 section, and still open the detail view when selected.
Thoughts
I could put them all into an AnyObject dictionary and when looking at individual items determine if they are of one object type or the other. I feel like that would work, but how would I go about sorting that correctly?
Put all common properties into a protocol, the build and sort an array of that common protocol:
protocol HasID {
var id: Int { get }
}
class TypeA : HasID, CustomStringConvertible {
var id: Int
init(_ id: Int) {
self.id = id
}
var description : String {
return ("TypeA(\(self.id))")
}
}
class TypeB : HasID, CustomStringConvertible {
var id: Int
init(_ id: Int) {
self.id = id
}
var description : String {
return ("TypeB(\(self.id))")
}
}
let typeA = [TypeA(1), TypeA(2), TypeA(5), TypeA(6)]
let typeB = [TypeB(3), TypeB(4), TypeB(7)]
let result: [HasID] = (typeA + typeB).sorted { $0.id < $1.id }
print(result)
[TypeA(1), TypeA(2), TypeB(3), TypeB(4), TypeA(5), TypeA(6), TypeB(7)]
Alternatively to Zoff Dino answer if you do not want to burden TypeA and TypeB classes with HasID protocol then you can define extension to these classes in your view controller:
class TypeA {
var ID: Int
init(_ id: Int) {
self.ID = id
}
}
class TypeB {
var ID: Int
init(_ id: Int) {
self.ID = id
}
}
protocol HasID {
var ID: Int { get }
}
// place this in your view controller
extension TypeA: HasID {
}
extension TypeB: HasID {
}
var arrayA = [TypeA(1), TypeA(3), TypeA(5)]
var arrayB = [TypeB(2), TypeB(4)]
let sortedArray = (arrayA.map { $0 as HasID } + arrayB.map { $0 as HasID })
.sort { $0.ID < $1.ID }
You can do this like so:
class TypeA {
var ID: Int
init(_ id: Int) {
self.ID = id
}
}
class TypeB {
var ID: Int
init(_ id: Int) {
self.ID = id
}
}
struct Wrap {
var ID: Int {
return a?.ID ?? b?.ID ?? 0
}
let a: TypeA?
let b: TypeB?
}
var arrayA = [TypeA(1), TypeA(3), TypeA(5)]
var arrayB = [TypeB(2), TypeB(4)]
let sortedArray = (arrayA.map { Wrap(a: $0, b: nil) } + arrayB.map { Wrap(a: nil, b: $0)})
.sorted { $0.ID < $1.ID }
When row is selected you can determine object with:
if let a = sortedArray[index].a {
// TypeA row selected
} else if let b = sortedArray[index].b {
// TypeB row selected
}

Using filter on Objects in an Array to find max? [swift]

I have a bunch of Objects stored in an Array.
They all have the property:
distanceInSeconds: Int
I was wondering if there's a way to find the max of this property between all objects in the array using filter or another array method?
For instance:
var distances: [Distance] = []
var maxDistance = distances.filter(find max)
This would be the Swifty way (by implementing Comparable):
class Route : Comparable {
let distance: Int
init(distance: Int) {
self.distance = distance
}
}
func ==(lhs: Route, rhs: Route) -> Bool {
return lhs.distance == rhs.distance
}
func <(lhs: Route, rhs: Route) -> Bool {
return lhs.distance < rhs.distance
}
let routes = [
Route(distance: 4),
Route(distance: 8),
Route(distance: 2),
Route(distance: 7)
]
print(routes.maxElement()?.distance)
output:
"8"
This works with Swift 2. If you're using Swift 1.2, maxElement(routes) should work
In Swift 2.0 minElement and maxElement now return optionals in case of empty sequences, and also now have versions that take isOrderedBefore closures.
let maxDistance = distances.maxElement { (a, b) -> Bool in
a.distanceInSeconds < b.distanceInSeconds
}
#1. The element type inside your sequence conforms to Comparable protocol
With Swift 4, if the element type inside your sequence conforms to Comparable protocol, you will be able to use the max() method that has the following declaration:
func max() -> Self.Element?
Returns the maximum element in the sequence.
Usage:
class Distance: Comparable, CustomStringConvertible {
let distanceInSeconds: Int
var description: String { return "Distance in Int: \(distanceInSeconds)" }
init(distanceInSeconds: Int) {
self.distanceInSeconds = distanceInSeconds
}
static func ==(lhs: Distance, rhs: Distance) -> Bool {
return lhs.distanceInSeconds == rhs.distanceInSeconds
}
static func <(lhs: Distance, rhs: Distance) -> Bool {
return lhs.distanceInSeconds < rhs.distanceInSeconds
}
}
let distances = [
Distance(distanceInSeconds: 20),
Distance(distanceInSeconds: 30),
Distance(distanceInSeconds: 10)
]
let maxDistance = distances.max()
print(String(describing: maxDistance)) // prints: Optional(Distance in Int: 30)
#2. The element type inside your sequence does not conform to Comparable protocol
With Swift 4, if the element type inside your sequence does not conform to Comparable protocol, you will have to use the max(by:) method that has the following declaration:
func max(by areInIncreasingOrder: ((offset: Int, element: Base.Element), (offset: Int, element: Base.Element)) throws -> Bool) rethrows -> (offset: Int, element: Base.Element)?
Returns the maximum element in the sequence, using the given predicate as the comparison between elements.
Usage:
class Distance: CustomStringConvertible {
let distanceInSeconds: Int
var description: String { return "Distance in Int: \(distanceInSeconds)" }
init(distanceInSeconds: Int) {
self.distanceInSeconds = distanceInSeconds
}
}
let distances = [
Distance(distanceInSeconds: 20),
Distance(distanceInSeconds: 30),
Distance(distanceInSeconds: 10)
]
let maxDistance = distances.max (by: { (a, b) -> Bool in
return a.distanceInSeconds < b.distanceInSeconds
})
print(String(describing: maxDistance)) // prints: Optional(Distance in Int: 30)
I think you want reduce:
Setup:
struct Distance {
var distanceInSeconds: Int
}
var distances: [Distance] = []
for _ in 1...10 {
distances += [Distance(distanceInSeconds: Int(arc4random_uniform(100)))]
}
Implementation:
let max = distances.reduce(distances.first) {
if let left = $0 where left.distanceInSeconds > $1.distanceInSeconds {
return $0
} else {
return $1
}
}

Resources