Combining two arrays of different types [duplicate] - ios

I'm trying to find the best way to merge Swift arrays, that are not of same type, but they have same superclass. I've already read all the tutorials so I know I can use:
var array = ["Some", "Array", "of", "Strings"]
array += ["Another string", "and one more"]
array.append(["Or", "This"])
In this case array variable infers the type [String]. The problem I have relates to the next hypothetical situation with classes (properties do not matter in this case, just there to make a difference between classes):
class A {
var property1 : String?
}
class B : A {
var property2: String?
}
class C : A {
var property3: String?
}
So I create an array of class A and B objects:
var array = [ A(), B(), A(), B() ]
This array should now be of type [A], since this is the inferred type by both A and B classes.
Now I want to append objects to this array, that are of type C.
var anotherArray = [ C(), C(), C() ]
Since anotherArray is now of type [C], we should still be able to append it, since all C instances respond to A methods. So we try:
array += anotherArray
This fails due to:
Binary operator '+=' cannot be applied to operands of type '[A]' and '[C]'.
Similar story with using append method. While this does make sense, I cannot understand why this couldn't work.
Can someone explain why this is not working? What is the best solution to this problem?
The only sensible solution I found is to define the type of anotherArray to be [A], but are there any better ones or this is correct?
var anotherArray : [A] = [ C(), C(), C() ]
Thanks!

If C inherits from A then you can "upcast" an array of type [C] to an array of type [A]
array += anotherArray as [A]
Alternatively, use (tested with Swift 4)
array.append(contentsOf: anotherArray)

In addition to Martin's answer, you could create a protocol that all of the classes conform to and then when creating your array, make it's type that protocol.
Then you can add any of the classes to it without casting.

you can merge almost everything. the only requirement is that all elements of resulting array must conform to the same protocol.
let arr1 = [1,2,3] // [Int]
let arr2 = [4.0,5.0,6.0] // [Double]
let arr3 = ["a","b"] // [String]
import Foundation // NSDate
let arr4 = [NSDate()] // [NSDate]
// the only common protocol in this case is Any
var arr:[Any] = []
arr1.forEach { arr.append($0) }
arr2.forEach { arr.append($0) }
arr3.forEach { arr.append($0) }
arr4.forEach { arr.append($0) }
print(arr) // [1, 2, 3, 4.0, 5.0, 6.0, "a", "b", 2016-02-15 08:25:03 +0000]

Related

Unable to compare array value in swift ios

I'm a fresher in iOS
I'm unable to compare in an if statement.
It looks like:
for i in 0.. <array.count
{
if(array[i] == array[i+1])
{
let removedVal = array.remove(i+1)
}
}
The error shows on the if condition:
Binary operator '==' cannot be applied to two 'Any' operands
I googled it, but I am unable to understand what should I do in my case.
=======================================================================
Atlast able to find a solution.
And it worked for me
if ( ((tempArrayForTeamName[i]) as AnyObject).isEqual(tempArrayForTeamName[i+1] as AnyObject) )
need to compare array index position as Any object
And use .isEqual replace of ==
You have to Filter your Array
var newarray = [Int]()
let dictionary = ["A":0,"B":1,"C":1,"D":1,"E":1,"F":1,"G":1,"H":1,"J":0]
let newDictionary = dictionary.reduce([:]) { result, element -> [String: Int] in
guard element.value != 1 else {
return result
}
var newResult = result
newResult[element.key] = element.value
newarray.append(newResult[element.key]!)
return newResult
}
In Swift : Array is a Generic Structure, NSMutableArray is an Objective-C class[will work in Swift].
A NSMutableArray created is of type Any; an array that can contain heterogenous object(could be String, Int or Bool).
An Array is arbitrarily specilized to contain Any (using as [Any])
eg:
var array:Array = ["ABC", 123, true] as [Any]
var nsMutableArray : NSMutableArray = ["ABC", 123, true]
Generic Parameterization:
Even if there is an option to give generic parameterization(Datatype) to your NSMutableArray in Objective C[remember NSMutableArray in an Objective C class],this generic parameterization in unfortunately ignored/not allowed in Swift.
How to specify the datatype:
In Swift one cannot specify the datatype of a NSMutableArray.It would give a compilation error: Cannot specialize non-generic type NSMutableArray.
But one can always specify the datatype of Array(Swift structure) as say: Array<String>.
eg: var array:Array<String> = ["Tom", "Jerry", "Spike"]
Your code has another problem, consider your array has 3 items then i=2, and you are trying to access index 3 (i+1). And program will crash.
Crash point (array[i] == array[i+1])
Please declare specific types array for example
let myArray:[String] = ["a", "b", "c", "d"]

Use of undeclared type 'Element' In Swift Extension Method (Array)

I am using Generics and protocol to make a name space for my Utils Class. and here when I goes to [Array] , I met some problem . here is the code :
in namespce.swift:
and in Array Extention:
can any one tell me how can i fix it?
Update:
I change my code to :
and here I have another problem , I have use "Self" in the function. but the T: Sequence type has no member of "index" .
Not sure what you are trying to achieve here (and if it's still relevant) but you should constrain your generic to RangeReplaceableCollection (to be able to use remove(at:)) instead of Sequence.
The firstIndex(of:) method (which returns the index of the first matching element) is available on Collection where Element: Equatable.
extension JX_TypeWrapper where T: RangeReplaceableCollection, T.Element: Equatable {
mutating func remove(object: T.Element) {
if let index = SELF.firstIndex(of: object) {
SELF.remove(at: index)
}
}
}
Which allows you to wrap an array into your JX_TypeWrapper:
var array: [Int] = [1, 2, 3]
var wrapped = JX_TypeWrapper(value: array)
wrapped.remove(object: 2)
wrapped.SELF // [1, 3]

Where in Swift is defined that we can use `[]` as Array literal?

I try to find in Swift documentation where it is defined, but I couldn't.
I expect something like following:
typealias [] = Array
typealias [Element] = Array<Element>
typealias [AnyObject] = Array<AnyObject>
So why it is possible to use [] instead of Array as initializer?
Edit depending on answer
I try to do the same with my custom Person class but it doesn't work:
class Person: ArrayLiteralConvertible {
typealias Element
public init(arrayLiteral elements: Self.Element...)
}
let personNames: Person = ["John", "Mark", "Kris"]
It's defined in the Summary of the Grammar, in the definition of array-literal:
array-literal → [ array-literal-items(opt) ]
array-literal-items → array-literal-item ,(opt) | array-literal-item , array-literal-items
array-literal-item → expression
In more "descriptive" text, this particular case is defined in The Swift Programming Language, Collection Types in the section on Arrays:
Creating an Empty Array
You can create an empty array of a certain type using initializer syntax:
var someInts: [Int] = []
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."
Note that the type of the someInts variable is inferred to be
[Int] from the type of the initializer.
To your updated question, the correct syntax (circa Swift 5, though your question is from and older version), would be:
class Person: ExpressibleByArrayLiteral {
required public init(arrayLiteral elements: String...) { ... }
}
You can write it a as a literal everything that conforms to literal protocols . Sets as Array conforms to ArrayLiteralConvertible protocol, you can declare a set by using the same array literal sintax and specifing the type to avoid compiler confusion or they still will be inferred as Array:
let set: Set = ["Hello","Bye"]
To conforms array literal protocol you must provide an initializer:
protocol ArrayLiteralConvertible {
typealias Element
init(arrayLiteral elements: Element...)
}
There is a nice post on NSHipster
Documentation define a literal as:
A literal is the source code representation of a value of a type, such
as a number or string.
Where it a literal first defined? I guess it's the duty of the compiler detect them and substitute with the proper type.

Syntax explanation: square brackets in Swift

I'm studying Swift and got confusing with following syntax:
var treasures: [Treasure] = []
Treasure is custom class, declared as follow:
class Treasure: NSObject { }
In Objective-C square brackets mean method, but what do they mean in Swift?
Ok, this is the meaning of
var treasures: [Treasure] = []
var: you are declaring a variable
treasures: the name of your variable
[Treasure]: the type of your variable, in this case the type is Array of Treasure, the compiler will allow you to insert only object of type Treasure in your Array
[]: the actual object (Array) referenced by your variable, in this case an empty Array.
E.g. if you want the Array to hold 2 elements you can write
var treasures: [Treasure] = [Treasure(), Treasure()]
Hope this helps.
Update:
My example can also be written this way
var treasures = [Treasure(), Treasure()]
Infact thanks to the Type Inference the compiler can deduce the type of the variable treasures looking at the type of the assigned value.
[Treasure] is just a syntax sugar for Array<Treasure>.
The same way [String:Treasure] is just a syntax sugar for Dictionary<String,Treasure>.
[] is just an empty array of the type you defined. The same way [:] is an empty dictionary.
When it comes to Swift and square brackets, the rules are simple. They are used only in two situations:
1) working with Array and Dictionary types:
let vectors : [[Int]] = [[1,2,3],[4,5,6]]
let birthBook : [Int:[String]] = [1987:["John","William"], 1990: ["Mary"]]
2) for subscripting objects that support subscripting:
class RouteMapper {
private var routeMap : [String:String] = [:]
subscript(endpoint: String) -> String {
get {
if let route = routeMap[endpoint] {
return route
}
return "/"
}
set(newValue) {
routeMap[endpoint] = newValue
}
}
}
let routeMapper = RouteMapper()
routeMapper["users"] = "/v1/confirmed/users"
let url = routeMapper["admins"]
Since [ and ] are not allowed in custom operators, these are the only usages for now.

Swift: different objects in one array?

Is there a possibility to have two different custom objects in one array?
I want to show two different objects in a UITableView and I think the easiest way of doing this is to have all objects in one array.
Depending on how much control you want over the array, you can create a protocol that both object types implement. The protocol doesn't need to have anything in it (would be a marker interface in Java, not sure if there is a specific name in Swift). This would allow you to limit the array to only the object types you desire. See the sample code below.
protocol MyType {
}
class A: MyType {
}
class B: MyType {
}
var array = [MyType]()
let a = A()
let b = B()
array.append(a)
array.append(b)
If you know the types of what you will store beforehand, you could wrap them in an enumeration. This gives you more control over the types than using [Any/AnyObject]:
enum Container {
case IntegerValue(Int)
case StringValue(String)
}
var arr: [Container] = [
.IntegerValue(10),
.StringValue("Hello"),
.IntegerValue(42)
]
for item in arr {
switch item {
case .IntegerValue(let val):
println("Integer: \(val)")
case .StringValue(let val):
println("String: \(val)")
}
}
Prints:
Integer: 10
String: Hello
Integer: 42
You can use AnyObject array to hold any kind of objects in the same array:
var objectsArray = [AnyObject]()
objectsArray.append("Foo")
objectsArray.append(2)
// And also the inmutable version
let objectsArray: [AnyObject] = ["Foo", 2]
// This way you can let the compiler infer the type
let objectsArray = ["Foo", 2]
You can use the "type" AnyObject which allows you to store objects of different type in an array. If you also want to use structs, use Any:
let array: [Any] = [1, "Hi"]

Resources