How to use two-dimensions array in Swift? - arrays

So I have this array var arrayItinerario: Array<Any> = [] which is intended to hold arrays of type Itinerario, var temporalArray: Array<Itinerario> = []
Next, this arrayItinerario would later be used to access properties from the struct Itinerario from where the array temporalArray type comes from.
cell.siteLabel.text = "\([arrayItinerario[indexPath.section]][indexPath.row].ubicacion)"
The problem is that arrayItinerario is not an Itinerario type object which make it impossible to access ubicacion to make an example
I have tried
let object = [arrayItinerario[indexPath.section]][indexPath.row] as! Itinerario
But the cast throws an error. How can I do to access properties from the arrays temporalArraythat are inside arrayItinerario?
Note: I am using indexPath because I am filling table cells

var arrayItinerario: [[Itinerario]] = []
//fill data
var temporalArray: [Itinerario] = []
arrayItinerario.append(temporalArray)
cell.siteLabel.text = "\(arrayItinerario[indexPath.section][indexPath.row].ubicacion)"
or
var arrayItinerario: Array<Any> = []
var temporalArray: Array<Itinerario> = []
guard let temp = arrayItinerario[indexPath.section] as? Array<Itinerario>{
return
}
cell.siteLabel.text = "\(temp[indexPath.row].ubicacion)"

Here's an implementation I've used in a few projects:
import Foundation
class Array2D<T> {
var cols:Int, rows:Int
var matrix:[T?]
init(cols: Int, rows: Int, defaultValue:T?) {
self.cols = cols
self.rows = rows
matrix = Array(repeating: defaultValue, count: cols*rows)
}
subscript(col:Int, row:Int) -> T? {
get{
return matrix[cols * row + col]
}
set{
matrix[cols * row + col] = newValue
}
}
func colCount() -> Int { self.cols }
func rowCount() -> Int { self.rows }
}
Because it's generic you can store whatever type you like in it. Example for Ints:
// Create 2D array of Ints, all set to nil initially
let arr = Array2D<Int>(cols: 10, rows: 10, defaultValue: nil)

Related

How can I merge 2 dictionaries into one array?

My JSON data look like this image below. Now I wanna merge the value of Shop Type and Promotion into one to use as collection view data. How can I do that?
I just filter the response data from the server like this:
var dataBanDau: [SDFilterModel] = []
var quickData: [SDFilterModel] = []
let filters: [SDFilterModel] = data
self.filterEntries = filters
//let nsarray = NSArray(array: self.filterEntries! , copyItems: true)
// self.filterEntriesStoreConstant = nsarray as! Array
self.dataBanDau = filters
for i in 0..<self.dataBanDau.count {
if self.dataBanDau[i].search_key.count == 0 {
self.quickData.append(self.dataBanDau[i])
}
}
self.quickData = self.quickData.filter {
$0.type != "range"
}
DispatchQueue.main.async {
//Note: Reload TableView
self.quickFilterCollection.reloadData()
completed(true)
}
}
the class SDFilterModel:
class SDFilterModel: DSBaseModel {
var name = String()
var type = String()
var is_expanded = Int()
var search_key = String()
var filterEntries : [SDFilterModel]?
override func copy(with zone: NSZone? = nil) -> Any {
// This is the reason why `init(_ model: GameModel)`
// must be required, because `GameModel` is not `final`.
let copy = SDFilterModel(dict: self.dictionary)
if let arrAttribute = NSArray(array: self.value , copyItems: true) as? [AttributeValueModel] {
copy.value = arrAttribute
}
return copy
}
override init(dict: Dictionary<String, Any>) {
super.init(dict: dict);
value = self.valueParse()
name = dict.getString(forKey: "name")
type = dict.getString(forKey: "type")
search_key = dict.getString(forKey: "search_key")
is_expanded = dict.getInt(forKey: "is_expanded")!
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var value: [AttributeValueModel] = [];
func valueParse()-> [AttributeValueModel] {
guard let childs = (self.dictionary["value"]) as? [Dictionary<String, AnyObject>]
else { return [] }
var output: [AttributeValueModel] = [];
for aDict in childs {
let item = AttributeValueModel(dict:aDict);
// if type == .Range && item.option_id == "0" {
// item.setRangeOptionID(aValue: item.option_name!)
// }
//
output.append(item);
}
return output;
}
Let be Assume you have let myArray = [1,2,3,4,5,6,7,8]
Now you wanted to square of each and every element in the array,
With for loop you do like this
for item in myArray {
print(item * item)
}
Now assume item = $0
With for map you jus do
myArray.map({ $0 * $0 })
Both will gave same output.
map : Use to do same operation on every element of array.
flatmap : It is used to flattern the array of array.
let myArr = [[1,2,3],[4,5,6,7]]
and you want o/p as [1,2,3,4,5,6,7]
So can get above output with myArr.flatMap({$0})
Now back to your question.
let reqArray = myModel.data.map({ $0.value }).flatMap({ $0 })
First, map gaves you array-of-array of key value but you need a single array, so for that you need to use flatmap.
You can take ref : https://medium.com/#Dougly/higher-order-functions-in-swift-sorted-map-filter-reduce-dff60b5b6adf
Create the models like this
struct Option {
let name: String
let searchKey: String
let id: String
}
struct Model {
let type: String
let name: String
let isExpanded: Bool
let value: [Option]
}
You should get the options array values and join all the arrays
let models:[Model] = //...
let collectionViewArray = models.map { $0.value }.reduce([Option](), +)
Using for loop
var collectionViewArray = [Option]()
for model in models {
collectionViewArray.append(contentsOf: model.value)
}

Combine / Merge Multiple Arrays Into One

I have four list of arrays:
var products: [Product] = []
var addressInfo: [AddressInfo] = []
var favorites: [Favorite] = []
var amounts: [Amount] = []
I want to combine them all into one so I have only one variable:
var combined = [Product/AddressInfo/Favorite/Amount]()
How would I go about merging them into one array var cobmbined = [Combined]() ?
This these are two examples of how my structs look like:
struct Amount {
var amountsDeliveryCharge: Double
var amountsDriverTip: Double
init(
amountsDeliveryCharge: Double,
amountsDriverTip: Double
){
self.amountsDeliveryCharge = amountsDeliveryCharge
self.amountsDriverTip = amountsDriverTip
}
init(data: [String: Any]){
amountsDeliveryCharge = data[DatabaseRef.deliveryCharge] as? Double ?? 0.0
amountsDriverTip = data[DatabaseRef.driverTip] as? Double ?? 0.0
}
static func modelToData(amount: Amount) -> [String: Any] {
let data : [String: Any] = [
DatabaseRef.deliveryCharge : amount.amountsDeliveryCharge,
DatabaseRef.driverTip : amount.amountsDriverTip
]
return data
}
}
This is the other struct:
struct Product {
var price: Double
var priceUnit: String
init(
price: Double,
priceUnit: String
){
self.price = price
self.priceUnit = priceUnit
}
init(data: [String: Any]){
price = data[DatabaseRef.price] as? Double ?? 0.0
priceUnit = data[DatabaseRef.priceUnit] as? String ?? ""
}
static func modelToData(product: Product) -> [String: Any] {
let data : [String: Any] = [
DatabaseRef.price : product.price,
DatabaseRef.priceUnit : product.priceUnit
]
return data
}
}
The other two structs look similar in structure as well.
Assuming the ordering is the same in each of them, create a struct with the appropriate properties
struct Combined {
let product: Product
let addressInfo: AddressInfo
let favourite: Favourite
let amount: Amount
}
and then either loop through the arrays using a counter to index then and create instances using the memberWise initialiser, or use a static factory function to make and return the array:
static func makeFrom(products: [Product], addresses: [AddressInfo], favourites: [Favourite], amounts: [Amount]) -> [Combined] {
guard products.count == addresses.count, addresses.count == favourites.count, favourites.count == amounts.count else {fatalError()}. //handle better in practice
var combined = [Combined]()
for index in 0..<products.count {
combined.append(Combined(product: products[index],
addressInfo: addresses[index],
favourite: favourites[index],
amount: amounts[index])
}
return combined
}
The above checks that all arrays are teh same length and if not calls fatalError(). In reality you'd want to handle the error better than this.
Then use as:
let combined = Combined.makeFrom(products: products, addresses:addressInfo, favourites: favourites, amounts: amounts)
You can cast your arrays as [Any] and add them.
let combinedVals = (products as [Any]) + (addressInfo as [Any]) + (favorites as [Any]) + (amounts as [Any])
Alternatively you can create a protocol and have your structs adhere to it.
protocol Combined {
}
struct Amount: Combined {
var amountsDeliveryCharge: Double
var amountsDriverTip: Double
}
struct Product: Combined {
var price: Double
var priceUnit: String
}
let combinedValues: [Combined] = amounts + products
When you iterate over the array, if you need to check what it is, you can use a switch to check it's type.
combinedValues.forEach { (value) in
switch value {
case let value as Amount:
print(value.amountsDriverTip)
break
case let value as Product:
print(value.price)
break
default:
break
}
}

How eliminate duplicate objects from array of objects in swift

I am having two arrays coming from web service, I need to find out whether the Array2 has the same objects as Array1.
So, For this I am using below code:
var arr1 = [CustomObject]()
var arr2 = [CustomObject]()
var arr3 = [CustomObject]()
var arr4 = [CustomObject]()
self.arr3 = self.arr1 + self.arr2 //concatenate two arrays
self.arr4 = Array(Set(arr3)) // find out uniq values
// below is the extension
extension Array where Element : Hashable {
var unique: [Element] {
var uniqueValues: [Element] = []
forEach { item in
if !uniqueValues.contains(item) {
uniqueValues += [item]
}
}
return uniqueValues
}
}
But it is showing error on above line "Array(Set(arr3))"
Error Is :- To add value to Set
Try this :
var arr1 = ["A","B","C"]
var arr2 = ["A","B","C"]
if Set(arr1).symmetricDifference(arr2).isEmpty {
print("The Arrays Match")
}
Overview:
In order for the set to store custom class / struct, the custom class / struct needs to to conform to Hashable protocol and indirectly Equatable protocol.
Given below is an example using a struct, you can use a class as well.
Code:
struct CustomObject : Hashable{
var something : Int //It is just an example, this could be any type, but some how you should find a way to compute the hash value.
//MARK: Hashable
var hashValue: Int {
return something
}
}
//MARK: CustomObject - Equatable
func ==(lhs: CustomObject, rhs: CustomObject) -> Bool {
return lhs.something == rhs.something
}

Addressing a multi-dimensional array of objects in Swift

Extreme newbie Swift syntax question...
Trying to address a multidimensional array of UIImageView objects and getting the error
Cannot subscript a value of type [[UIImageView]] with an index of
type UInt32.
I thought I was creating an NxN array of UIImageView objects but I guess not?
Thanks All!
func loadDefaultImages()
{
var pictures : [[UIImageView]] = [];
let MaxRows: UInt32 = 4
let MaxCols: UInt32 = 4
var row: UInt32
var col: UInt32
for (row = 0; row <= MaxRows; row++)
{
for (col = 0; col <= MaxCols; col++)
{
var newImage = UIImageView(image: UIImage(named: "first"))
pictures[row][col] = UIImageView() /* Error on this statement */
}
}
}
Initially, your pictures array will not contain any elements, (i.e. it will evaluate to []). As you try to set pictures[0][0], you're trying to reference both a row and column that do not exist yet.
Instead, you could build up the array as you go, like this:
func loadDefaultImages() {
var pictures : [[UIImageView]] = [];
let MaxRows: UInt32 = 4
let MaxCols: UInt32 = 4
for _ in 0..<MaxRows {
var aRow : [UIImageView] = []
for _ in 0..<MaxCols {
let newImage = UIImageView(image: UIImage(named: "first"))
aRow.append(newImage)
}
pictures.append(aRow)
}
}
However, a neater way to do this would be to create the array with a default size using the count, repeatedValue function, like so:
func loadDefaultImages() {
let MaxRows: Int = 4
let MaxCols: Int = 4
var pictures = [[UIImageView?]](count: MaxRows, repeatedValue: [UIImageView?](count: MaxCols, repeatedValue: nil))
for row in 0..<MaxRows {
for col in 0..<MaxCols {
let newImage = UIImageView(image: UIImage(named: "first"))
pictures[row][col] = newImage
}
}
}

Swift 2.0 - ERROR: Immutable value of type '[String]' only has mutating members named 'append'

I am trying to write a method which extracts a HTML tag into a array because I want to parse a web page in a tree structure.
func extractStringFromHTMLInsideTags(htmlString:String, htmlTagPairArray:[String], saveToArray:[String]) -> String
{
var htmlNSString = htmlString as NSString
var lenght = htmlNSString.length
var openingTag = htmlTagPairArray[0] as NSString
var openingTagLength = openingTag.length
var closingTag = htmlTagPairArray[1] as NSString
var closingTagLength = closingTag.length
if (htmlString.rangeOfString(htmlTagPairArray[0]) != nil)
{
let rangeStart:NSRange! = htmlNSString.rangeOfString(htmlTagPairArray[0], options: NSStringCompareOptions.CaseInsensitiveSearch)
var rangeEnd:NSRange! = htmlNSString.rangeOfString(htmlTagPairArray[1], options: NSStringCompareOptions.CaseInsensitiveSearch)
let startTagIndex: Int = rangeStart.location + openingTagLength
let boldTextLenght: Int = rangeEnd.location - rangeStart.location - openingTagLength
let endTagIndex: Int = startTagIndex + boldTextLenght
let startIndex = advance(htmlString.startIndex,startTagIndex)//advance as much as you like
let endIndex = advance(htmlString.startIndex,endTagIndex)
let range = startIndex..<endIndex
var resultString = htmlString.substringWithRange( range )
saveToArray.append(resultString)
resultString = htmlString.stringByReplacingOccurrencesOfString(htmlTagPairArray[0] + resultString + htmlTagPairArray[1], withString: resultString, options: nil, range: nil)
if (resultString.rangeOfString(htmlTagPairArray[0]) != nil)
{
resultString = extractStringFromHTMLInsideTags(resultString,htmlTagPairArray:htmlTagPairArray, saveToArray:saveToArray)
}
return resultString
}
return htmlString
}
On the line:
saveToArray.append(resultString)
I am getting the error:
Immutable value of type '[String]' only has mutating members named
'append'
The error states that saveToArray is immutable. I thought that the array is copied by reference...?
Why is this happening?
( I am using Swift 2.0 and Xcode 7.1 ).
Parameters passed in methods are immutable (let) by default.
Add the keyword var to make them mutable
func extractStringFromHTMLInsideTags(htmlString:String, htmlTagPairArray:[String], var saveToArray:[String]) -> String
{ ...

Resources