I've got two function. They are doing the same thing actually. Getting data from database results by fieldNameArray into array of Int or Double.. how can i merge these two functions into one ? is that possible ? only difference is fields type and so return type..
func fieldsToInt ( fieldNameArray : [String] ) -> [Int] {
var returnArray = [Int]()
for fNA in fieldNameArray {
let n = Int ( results.int(forColumn: fNA) )
returnArray.append( n )
}
return returnArray;
}
func fieldsToDouble ( fieldNameArray : [String] ) -> [Double] {
var returnArray = [Double]()
for fNA in fieldNameArray {
let n = Double ( results.int(forColumn: fNA) )
returnArray.append( n )
}
return returnArray;
}
You can try generics, like
func fieldsToNumber<T> ( fieldNameArray : [String] ) -> [T] {
var returnArray = [T]()
for fNA in fieldNameArray {
let n = T ( results.int(forColumn: fNA) )
returnArray.append( n )
}
return returnArray;
}
Yes, it is possible, you should use Generics, in particular you need a generic function.
The code that solves your problem would roughly look like this:
// This is a struct to mock the code you didn't post
struct Results {
func int(forColumn: String) -> Int16 {
return 1
}
}
let results = Results()
protocol DatabaseElementRepresentable {
init?(_ databaseValue: Int16)
}
func fields<Element: DatabaseElementRepresentable>(fieldNameArray : [String]) -> [Element] {
var returnArray = [Element]()
for fNA in fieldNameArray {
if let n = Element(results.int(forColumn: fNA)) {
returnArray.append(n)
}
}
return returnArray
}
extension Int: DatabaseElementRepresentable { }
extension Double: DatabaseElementRepresentable { }
let ints: [Int] = fields(fieldNameArray: ["test"])
let doubles: [Double] = fields(fieldNameArray: ["test"])
Please, change Int16 with the value the function int(forColumn: returns
Related
The algorithm below checks to see if an array has at least two or more duplicates. It uses a dictionary to store the occurrences; the time complexity is linear because it has to traverse the dictionary to see if a key occurs twice. In swift, how can I look up a value to see if it occurs more than twice in constant time ?
func containsDuplicate(_ nums: [Int]) -> Bool {
var frequencyTable = [Int:Int]()
for num in nums {
frequencyTable[num] = (frequencyTable[num] ?? 0 ) + 1
}
for value in frequencyTable.values{
if value >= 2 {
return true
}
}
return false
}
containsDuplicate([1,1,2,3,3,3,3,4])
The second loop is not necessary if the first loop checks if the current element has already been inserted before, and returns from the function in that case:
func containsDuplicate(_ nums: [Int]) -> Bool {
var frequencyTable = [Int:Int]()
for num in nums {
if frequencyTable[num] != nil {
return true
}
frequencyTable[num] = 1
}
return false
}
Then it becomes apparent that we don't need a dictionary, a set is sufficient:
func containsDuplicate(_ nums: [Int]) -> Bool {
var seen = Set<Int>()
for num in nums {
if seen.contains(num) {
return true
}
seen.insert(num)
}
return false
}
This can be further simplified: The “insert and check if element was already present” operation can be done in a single call:
func containsDuplicate(_ nums: [Int]) -> Bool {
var seen = Set<Int>()
for num in nums {
if !seen.insert(num).inserted {
return true
}
}
return false
}
This is similar to the solution from this answer
return nums.count != Set(nums).count
but possibly more efficient: The function returns immediately when a duplicate element has been detected.
Finally we can make the function generic, so that it works with all arrays of a hashable type:
func containsDuplicate<T: Hashable>(_ array: [T]) -> Bool {
var seen = Set<T>()
for element in array {
if !seen.insert(element).inserted {
return true
}
}
return false
}
Example:
print(containsDuplicate([1,1,2,3,3,3,3,4])) // true
print(containsDuplicate(["A", "X"])) // false
Or as an extension for arbitrary collections of a hashable type:
extension Collection where Element: Hashable {
func containsDuplicate() -> Bool {
var seen = Set<Element>()
for element in self {
if !seen.insert(element).inserted {
return true
}
}
return false
}
}
print([1,1,2,3,3,3,3,4].containsDuplicate())
print(["A", "X"].containsDuplicate())
You just want to know if it has duplicate, you can use use set and compare the length.
func containsDuplicate(_ nums: [Int]) -> Bool {
return Set(nums).count != nums.count
}
like this examples, because the set remove the duplicate values.
I have the below structs in my project:
struct templateScheduleResponse: Decodable {
let templateScheduleTypes: [scheduleTemplateType]
}
struct scheduleTemplateType: Decodable {
let templateScheduleNames: [templateScheduleName]?
let templateTypeId: String?
let templateTypeName: String
}
struct templateScheduleName: Decodable {
let templateNameId: String?
let templateSchedName: String
}
and I want to sort it so that the array of templateScheduleName is sorted by templateSchedName value.
I'm completely stuck on how to do this.
Any pointers, please? (I'm just started learning Structs, if you couldn't tell!)
Thanks!
UPDATE: Here is my JSON data:
{
templateScheduleTypes = (
{
templateScheduleNames = (
{
templateNameId = "fad562bc-4510-49ea-b841-37a825a2f835";
templateSchedName = "Daily_Intensive";
},
{
templateNameId = "fdeeb79f-6321-4ff6-b1f0-8272a018e73b";
templateSchedName = "Weekly_Full_Log_Directories";
},
{
templateNameId = "84f9800f-da18-44b8-822f-830069dcc594";
templateSchedName = "Weekly_Full";
},
{
templateNameId = "47a6f050-13d7-4bf6-b5db-ab53e0a3aa54";
templateSchedName = "Weekly_Full_Catalog_Two_Weeks";
},
{
templateNameId = "b8ef9577-e871-4d79-8d3a-cfe958c0c3aa";
templateSchedName = "Weekly_Full_Over_WAN";
},
{
templateNameId = "8d507f52-0d74-404e-ad0d-76e6a7a94287";
templateSchedName = "Monthly_Full";
}
);
templateTypeId = "4e73b9ea-71d0-4abd-83c6-7d7b6d45641b";
templateTypeName = datalist;
},
{
templateScheduleNames = (
{
templateNameId = "39386552-45a5-4470-b152-7be00583e767";
templateSchedName = "Scheduled_Exchange_Server";
}
);
templateTypeId = "a7c28240-c187-4f86-818c-efd86fb26c7d";
templateTypeName = MSESE;
},
{
templateScheduleNames = (
{
templateNameId = "0037846c-d1fe-4c8f-8eec-c62681a12a57";
templateSchedName = "Scheduled_Exchange_Single_Mailbox";
}
);
templateTypeId = "9e06f06a-11dc-44b8-97a0-68bd0b45a07a";
templateTypeName = Mailbox;
}
);
}
You can do an ad hoc sort without having to conform to Comparable. If x is some variable of type templateScheduleType:
x.templateScheduleNames.sorted(by: { (lhs, rhs) -> Bool in
return lhs.templateSchedName < rhs.templateSchedName
})
If you want to ensure the array is sorted in place at construction time, define an init method on scheduleTemplateType just as you would on a class:
init(scheduleNames: [templateScheduleName], typeID:String?, typeName:String) {
self.templateScheduleNames = scheduleNames.sorted(by: { (lhs, rhs) -> Bool in
return lhs.templateSchedName < rhs.templateSchedName
})
self.templateTypeId = typeID
self.templateTypeName = typeName
}
First of all struct names should begin with an uppercase char.
To answer your question, you need to make TemplateScheduleName
struct TemplateScheduleName: Decodable {
let templateNameId: String?
let templateSchedName: String
}
conform to Comparable
extension TemplateScheduleName: Comparable {
static func ==(lhs: TemplateScheduleName, rhs: TemplateScheduleName) -> Bool {
return lhs.templateSchedName == rhs.templateSchedName
}
public static func <(lhs: TemplateScheduleName, rhs: TemplateScheduleName) -> Bool {
return lhs.templateSchedName < rhs.templateSchedName
}
}
Now given
let list : [TemplateScheduleName] = []
you can easily sort it
let sortedList = list.sorted()
The code below is written in order to group journal publications by year of publication.
But I got the error "Cannot convert value of type '(Journal) -> Int' to expected argument type '(_) -> _'"
Here's the playground with a stripped down version of the real code for you to play around http://swiftlang.ng.bluemix.net/#/repl/1de81132cb2430962b248d2d6ff64922e2fe912b1480db6a7276c6a03047dd89
class Journal {
var releaseDate: Int = 0
static var journals = [Journal]()
class func groupedReduce<S: SequenceType, K: Hashable, U> (
source: S,
initial: U,
combine: (U, S.Generator.Element) -> U,
groupBy: (S.Generator.Element) -> K
)
-> [K:U]
{
var result: [K:U] = [:]
for element in source {
let key = groupBy(element)
result[key] = combine(result[key] ?? initial, element)
}
return result
}
class func groupBy() {
let byYear = { (journal: Journal) in
journal.releaseDate
}
let groupedJournals = groupedReduce(journals, initial: 0, combine:+, groupBy: byYear)
print("Grouped journals = \(groupedJournals)")
}
}
Journal.journals = [Journal(), Journal(), Journal(), Journal()]
for j in Journal.journals {
j.releaseDate = 1
}
Journal.groupBy()
Your code is overly complicated. Below is a groupBy function that group elements of an array according to criteria of your choice. Playground
import Foundation
class Journal {
var releaseDate: Int = 0
init(_ releaseDate: Int) {
self.releaseDate = releaseDate
}
}
extension Array {
func groupBy<T: Hashable>(f: Element -> T) -> [T: [Element]] {
var results = [T: [Element]]()
for element in self {
let key = f(element)
if results[key] == nil {
results[key] = [Element]()
}
results[key]!.append(element)
}
return results
}
func groupBy2<T: Hashable>(f: Element -> T) -> [T: [Element]] {
return self.reduce([T: [Element]]()) { (var aggregate, element) in
let key = f(element)
if aggregate[key] == nil {
aggregate[key] = [Element]()
}
aggregate[key]!.append(element)
return aggregate
}
}
}
let journals = [Journal(2015), Journal(2016), Journal(2015), Journal(2014)]
let groupedJournals = journals.groupBy {
$0.releaseDate
}
print(groupedJournals)
I am using the following code in xCode 6.4 to split strings inside an array into arrays:
func getData() -> [String]
{
let data = navData
// navData is like:
// A|xxx|xxx|xxx
// R|ccc|ccc|ccc
// N|ccc|ccc|ccc
// N|ccc|ccc|ccc
return split(data) { $0 == "\n" }
}
let data:[String] = getData()
func search(query:(String, Int)) -> [String]
{
let recs:[String] = data.filter { $0.hasPrefix(query.0) }
var cols: [String] = recs.map { split( recs ) { $0 == "|" } }
}
func searchQueries() -> [(String, Int)]
{
return [("N", 1)] //key, column index
}
for q:(String, Int) in searchQueries()
{
var results:[String] = search(q)
for x in results
{
result = results[0]
}
}
It used to work before, but I guess swift was changed in 1.2 and it gives the following error now:
Cannot invoke 'map' with an argument list of type '(() -> _)'
Any suggestions?
Thank you!
After discovering that in Swift two you have to split strings by using its characters property, I made this work in playground:
let recs = ["col1|col2|col3", "1|2|3"]
let cols = recs.map {
split($0.characters) { $0 == "|" }.map {String($0)}
}
cols.first // ["col1", "col2", "col3"]
cols.last // ["1", "2", "3"]
Note that in Swift 2 beta 2 you can also use {String.init} at the end.
To make this work in Swift 1.2, remove .characters.
How would I go about implementing a custom enumerate function that makes something like this work (Swift 2):
for ((column, row), item) in Array2D.enumerate() { ... }
In my simple Array2D struct:
struct Array2D<T> : SequenceType {
let columns: Int
let rows: Int
private var array: Array<T?>
init(columns: Int, rows: Int) {
self.columns = columns
self.rows = rows
array = Array(count: rows*columns, repeatedValue: nil)
}
subscript(column: Int, row: Int) -> T? {
get {
return array[columns*row + column]
}
set {
array[columns*row + column] = newValue
}
}
func generate() -> AnyGenerator<T?> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return item
}
}
}
I couldn't find any good explanation on implementing an enumerate function in Swift
The enumerate() function in Swift returns integers starting from 0 for the first part of its tuple. Those have nothing to do with the sequence you're enumerating over. So, for instance, this won't work:
let word = "hello".characters
for (index, letter) in word.enumerate() {
print(word[index])
}
Because the indices of a characterView are String.Indexs.
So there are several ways to get what you're going for. The first is to just overload enumerate() for your struct. Again, there are a few days you could do this. First off, how about a function that uses your own generator, and uses its own logic to figure out the coordinates. This could work:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
let g = self.generate()
var coord = -1
return anyGenerator {
g.next().map { ((++coord % self.columns, coord / self.columns), $0) }
}
}
But you're duplicating code there, especially from your generate method. Seeing you're already using coordinates to return each element, why not just have your enumerate method be the default, and your generate method call on that. Something like this:
// Original generate method, now returns the coords it used
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return ((column, row), item)
}
}
// uses enumerate, ignores coords
func generate() -> AnyGenerator<T?> {
let g = self.enumerate()
return anyGenerator {
g.next().map { $1 }
}
}
If you wanted to go a little overboard, you could write an enumerate function that enumerates the specific indices of its base. Call it specEnumerate:
public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
private var eG: Base.Generator
private let sI: Base.Index
private var i : Base.Index?
public mutating func next() -> (Base.Index, Base.Generator.Element)? {
i?._successorInPlace() ?? {self.i = self.sI}()
return eG.next().map { (i!, $0) }
}
private init(g: Base.Generator, i: Base.Index) {
self.eG = g
self.sI = i
self.i = nil
}
}
public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
private let col: Base
public func generate() -> SpecEnumerateGen<Base> {
return SpecEnumerateGen(g: col.generate(), i: col.startIndex)
}
}
public extension CollectionType {
func specEnumerate() -> SpecEnumerateSeq<Self> {
return SpecEnumerateSeq(col: self)
}
}
With this function, this would work:
let word = "hello".characters
for (index, letter) in word.specEnumerate() {
print(word[index])
}
But your matrix struct is still a SequenceType, with no specific indices. For that, you'll have to implement your own MatrixIndex:
public struct MatrixIndex: BidirectionalIndexType {
public let x, y : Int
private let columns: Int
public func successor() -> MatrixIndex {
return (x + 1 == columns) ?
MatrixIndex(x: 0, y: y + 1, columns: columns) :
MatrixIndex(x: x + 1, y: y, columns: columns)
}
public func predecessor() -> MatrixIndex {
return (x == 0) ?
MatrixIndex(x: columns - 1, y: y - 1, columns: columns) :
MatrixIndex(x: x - 1, y: y, columns: columns)
}
}
public func == (lhs: MatrixIndex, rhs: MatrixIndex) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
extension MatrixIndex : CustomDebugStringConvertible {
public var debugDescription: String {
return "\(x), \(y)"
}
}
extension MatrixIndex: RandomAccessIndexType {
public func advancedBy(n: Int) -> MatrixIndex {
let total = (y * columns) + x + n
return MatrixIndex(x: total % columns, y: total / columns, columns: columns)
}
public func distanceTo(other: MatrixIndex) -> Int {
return (other.x - x) + (other.y - y) * columns
}
}
Right. Now you'll need another matrix struct:
public struct Matrix2D<T> : MutableCollectionType {
public var contents: [[T]]
public subscript(index: MatrixIndex) -> T {
get {
return contents[index.y][index.x]
} set {
self.contents[index.y][index.x] = newValue
}
}
public var count: Int { return contents[0].count * contents.count }
public var startIndex: MatrixIndex {
return MatrixIndex(x: 0, y: 0, columns: contents[0].count)
}
public var endIndex: MatrixIndex {
return MatrixIndex(x: 0, y: contents.endIndex, columns: contents[0].count)
}
}
Right. So now, after all of that, this works:
let myMatrix = Matrix2D(contents: [[1, 2], [3, 4]])
for (coordinate, value) in myMatrix.specEnumerate() {
value == myMatrix[coordinate] // True every time
}
It might suffice defining your own enumerate taking advantage of the one you already have:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var index = 0
var g = array.generate()
return anyGenerator() {
if let item = g.next() {
let column = index % self.columns
let row = index / self.columns
++index
return ((column, row) , item)
}
return nil
}
}
Notice in this case you could avoid conforming to SequenceType since I use generate from the private array. Anyway it could be consistent to do so.
Here is how then you could use it:
var a2d = Array2D<Int>(columns: 2, rows: 4)
a2d[0,1] = 4
for ((column, row), item) in a2d.enumerate() {
print ("[\(column) : \(row)] = \(item)")
}
Hope this helps