How can I write a method that takes in a string input and prints the first most repeated character in that string - arrays

I was trying to make a function that can iterate through any string and return the most common character within that string. My progress is shown below. I was trying to insert the character array into a dictionary where I could then print out the dictionary containing every character and their count. For the people that Think no effort was put in, I merely left out all of the code that I have tried and commented out. Didn't see any use for that so only the essentials were included.
let str = "sunday, monday, happy days"
var charStr = Array(str.characters)
var charDict = Dictionary<Character,Int>()
print("This is the character string array: " , charStr)

You can easily iterate through your characters and increase the number of occurrences of it in your dictionary:
Swift 3
let str = "sunday, monday, happy days"
var charDict: [Character: Int] = [:]
for char in str.characters {
charDict[char] = (charDict[char] ?? 0) + 1
}
print(charDict) // ["d": 3, "u": 1, "a": 4, "h": 1, ",": 2, "n": 2, " ": 3, "m": 1, "o": 1, "y": 4, "s": 2, "p": 2]
You can use max method on your character collection to get the maximum value of your dictionary
if let mostFrequent = charDict.max(by: { $0.value < $1.value }) {
let chars = charDict.filter { $0.value == mostFrequent.value }
.map { $0.key }
.sorted()
print("The most frequent characters are:", chars) // ["a", "y"]
print("Number of occurences:", mostFrequent.value) // 4
}
The most frequent character is: a
Number of occurences: 4

Related

Swift Comparing Elements of Two Separate Arrays

I am trying to compare the elements in two different arrays in Swift without using higher order functions. The function should return an array of integers that are in both arrays. I think I am close, but am getting 'an index out range error. Also would like to know how this measures on time complexity
let arrayOne = [1, 5, 12, 3, -15 , 52, 20]
let arrayTwo = [3, 1, 6, 5, 57, 13, 17, 20]
func compareElementsInArray(array1:[Int], array2: [Int]) -> [Int] {
let totalArray = array1 + array2
var sortedArray = totalArray.sorted()
var results = [Int]()
for i in totalArray {
if sortedArray[i + 1] == sortedArray[i] {
results.append(sortedArray[i])
}
}
return results
}
compareElementsInArray(array1: arrayOne, array2: arrayTwo)
The problem is that you are iterating through all element of totalArray meaning that i will reach the last index of totalArray, then you are trying to access the i+1-th element of sortedArray, which has the same length as totalArray, hence the error.
You need to stop the loop at the index before the last one, not the last one.
func compareElementsInArray(array1:[Int], array2: [Int]) -> [Int] {
let totalArray = array1 + array2
var sortedArray = totalArray.sorted()
var results = [Int]()
for i in 0..<totalArray.count-1 {
if sortedArray[i + 1] == sortedArray[i] {
results.append(sortedArray[i])
}
}
return results
}
print(compareElementsInArray(array1: arrayOne, array2: arrayTwo))
However, you can use an NSCountedSet to achieve the same using higher order functions (your solutions doesn't actually use higher order functions).
You just have to create a counted set from the combination of the arrays, then use flatMap to filter the elements whose count is greater than 1 and map the result to [Int].
func nonUniqueElements(array1: [Int], array2: [Int])->[Int] {
let countedSet = NSCountedSet(array: array1+array2)
return countedSet.flatMap({ element in
if countedSet.count(for: element) > 1 {
return element as? Int
} else {
return nil
}
})
}
nonUniqueElements(array1: arrayOne, array2: arrayTwo)

Convert string into array without quotation marks in Swift 3

My question:
This answer explains how to convert a String containing elements separated by spaces into an array.
let numbers = "1 2 3 4"
let numbersArray = numbers.components(separatedBy: " ")
print(numbersArray)
// output: ["1", "2", "3", "4"]
// but I want: [1, 2, 3, 4]
However, I'm trying to make an array without quotation marks, because I'm making an array of numbers, not strings.
My attempts:
I tried removing all quotation marks from numbersArray, but this didn't work as it's an array, not a string.
numbersArray.replacingOccurrences(of: "\"", with: "") // won't work
I tried something different: I tried adding each element in the array to a new array, hoping that new array wouldn't contain quotation marks. I got an error, though:
let numbers = "1 2 3 4" // string to be converted into array without quotes
let numbersArray = numbers.components(separatedBy: " ") // convert string into array with quotes
var newNumbersArray = [String]() // new blank array (which will be without quotes)
for i in numbersArray { // for each item in the array with quotes
newNumbersArray += i // (hopefully) add the item in the new array without quotes
}
print(newNumbersArray) // print the new array
This gives me an error:
Swift:: Error: cannot convert value of type '[String]' to expected argument type 'inout String'
newNumbersArray += i
You can apply a flatMap call on the [String] array resulting from the call to components(separatedBy:), applying the failable init(_:radix:) of Int in the body of the transform closure of the flatMap invokation:
let strNumbers = "1 2 3 4"
let numbersArray = strNumbers
.components(separatedBy: " ")
.flatMap { Int($0) }
print(numbersArray) // [1, 2, 3, 4]
print(type(of: numbersArray)) // Array<Int>
You can try this:
var newArray = [Int]()
for item in numbersArray{
newArray.append(Int(item))
}
print(newArray)
Swift 3.0
Try this.. Chaining method makes it easy.
let temp = "1 2 3 4 5 6"
var numbers: [Int] = []
temp.components(separatedBy: " ").forEach { numbers.append(Int($0)!) }
print(numbers) //[1, 2, 3, 4, 5, 6]

Swift 3: Split string into Array of Int

I'm trying to split string into Array Of integers:
let stringNumbers = "1 2 10"
var arrayIntegers = stringNumbers.characters.flatMap{Int(String($0))}
But my problem is I'm getting this output:
[1, 2, 1, 0]
When I should be getting this output:
[1, 2, 10]
What I'm doing wrong?
I'll really appreciate your help.
Use this
let stringNumbers = "1 2 10"
let array = stringNumbers.components(separatedBy: " ")
let intArray = array.map { Int($0)!} // [1, 2, 10]
You are converting the individual characters of the strings into numbers. First the 1, then the space, then the 2, then the space, then the 1, and lastly the 0. If course converting the space gives a nil with is filtered out by using flatMap.
You can do:
let stringNumbers = "1 2 10"
var arrayIntegers = stringNumbers.components(separatedBy: " ").flatMap { Int($0) }
This splits the original string into an array of strings (separated by a space) and then maps those into integers.
In Swift 5 it is:
let stringNumbers = "1 2 10"
var arrayIntegers = stringNumbers.split(separator: " ").compactMap { Int($0) }

Convert array.count to String

I need to convert an array.count to String values for the count, i.e.
array.count = 5 should return ["0","1","2","3","4"]
I've tried
var strRow = array.map { String($0) }
return strRow
but it's not working the way it should. Any help will be appreciated.
Try
return Array(0...array.count)
if you want array of Strings, then just map it
Array(0...array.count).map{String($0)}
Try this (Hint are in the Code Comments):
var array = [1, 2, 3, 4, 5] // array.count = 5
var stringArray = [String]()
// 0 ... array.count to go from 0 to 5 included
for index in 0 ... array.count {
// append index with cast it to string
stringArray.append(String(index))
}
print(stringArray)
// result -> ["0","1","2","3","4","5"]
In your question you give an example that array of count 5 should be transformed to ["0","1","2","3","4","5"], that's a 6-count array, are you sure this is what you need? I will assume that you want 5-count array to be transformed to ["0","1","2","3","4"], please correct me in the comments if I'm wrong.
Here's the solution I propose:
let array = [5,5,5,5,5] // count 5
let stringIndices = array.indices.map(String.init)
// ["0", "1", "2", "3", "4"]

Find min / max value in Swift Array

Given an array of Swift numeric values, how can I find the minimum and maximum values?
I've so far got a simple (but potentially expensive) way:
var myMax = sort(myArray,>)[0]
And how I was taught to do it at school:
var myMax = 0
for i in 0..myArray.count {
if (myArray[i] > myMax){myMax = myArray[i]}
}
Is there a better way to get the minimum or maximum value from an integer Array in Swift? Ideally something that's one line such as Ruby's .min and .max.
Given:
let numbers = [1, 2, 3, 4, 5]
Swift 3:
numbers.min() // equals 1
numbers.max() // equals 5
Swift 2:
numbers.minElement() // equals 1
numbers.maxElement() // equals 5
To calculate an array's min and max values yourself, you can use reduce. This was a key solution prior to .min() and .max() appearing in Swift.
Use the almighty reduce:
let nums = [1, 6, 3, 9, 4, 6];
let numMax = nums.reduce(Int.min, { max($0, $1) })
Similarly:
let numMin = nums.reduce(Int.max, { min($0, $1) })
reduce takes a first value that is the initial value for an internal accumulator variable, then applies the passed function (here, it's anonymous) to the accumulator and each element of the array successively, and stores the new value in the accumulator. The last accumulator value is then returned.
With Swift 5, Array, like other Sequence Protocol conforming objects (Dictionary, Set, etc), has two methods called max() and max(by:) that return the maximum element in the sequence or nil if the sequence is empty.
#1. Using Array's max() method
If the element type inside your sequence conforms to Comparable protocol (may it be String, Float, Character or one of your custom class or struct), you will be able to use max() that has the following declaration:
#warn_unqualified_access func max() -> Element?
Returns the maximum element in the sequence.
The following Playground codes show to use max():
let intMax = [12, 15, 6].max()
let stringMax = ["bike", "car", "boat"].max()
print(String(describing: intMax)) // prints: Optional(15)
print(String(describing: stringMax)) // prints: Optional("car")
class Route: Comparable, CustomStringConvertible {
let distance: Int
var description: String { return "Route with distance: \(distance)" }
init(distance: Int) {
self.distance = distance
}
static func ==(lhs: Route, rhs: Route) -> Bool {
return lhs.distance == rhs.distance
}
static func <(lhs: Route, rhs: Route) -> Bool {
return lhs.distance < rhs.distance
}
}
let routes = [
Route(distance: 20),
Route(distance: 30),
Route(distance: 10)
]
let maxRoute = routes.max()
print(String(describing: maxRoute)) // prints: Optional(Route with distance: 30)
#2. Using Array's max(by:) method
If the element type inside your sequence does not conform to Comparable protocol, you will have to use max(by:) that has the following declaration:
#warn_unqualified_access func max(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> Element?
Returns the maximum element in the sequence, using the given predicate as the comparison between elements.
The following Playground codes show to use max(by:):
let dictionary = ["Boat" : 15, "Car" : 20, "Bike" : 40]
let keyMaxElement = dictionary.max(by: { (a, b) -> Bool in
return a.key < b.key
})
let valueMaxElement = dictionary.max(by: { (a, b) -> Bool in
return a.value < b.value
})
print(String(describing: keyMaxElement)) // prints: Optional(("Car", 20))
print(String(describing: valueMaxElement)) // prints: Optional(("Bike", 40))
class Route: CustomStringConvertible {
let distance: Int
var description: String { return "Route with distance: \(distance)" }
init(distance: Int) {
self.distance = distance
}
}
let routes = [
Route(distance: 20),
Route(distance: 30),
Route(distance: 10)
]
let maxRoute = routes.max(by: { (a, b) -> Bool in
return a.distance < b.distance
})
print(String(describing: maxRoute)) // prints: Optional(Route with distance: 30)
The other answers are all correct, but don't forget you could also use collection operators, as follows:
var list = [1, 2, 3, 4]
var max: Int = (list as AnyObject).valueForKeyPath("#max.self") as Int
you can also find the average in the same way:
var avg: Double = (list as AnyObject).valueForKeyPath("#avg.self") as Double
This syntax might be less clear than some of the other solutions, but it's interesting to see that -valueForKeyPath: can still be used :)
You can use with reduce:
let randomNumbers = [4, 7, 1, 9, 6, 5, 6, 9]
let maxNumber = randomNumbers.reduce(randomNumbers[0]) { $0 > $1 ? $0 : $1 } //result is 9
Swift 3.0
You can try this code programmatically.
func getSmallAndGreatestNumber() -> Void {
let numbers = [145, 206, 116, 809, 540, 176]
var i = 0
var largest = numbers[0]
var small = numbers[0]
while i < numbers.count{
if (numbers[i] > largest) {
largest = numbers[i]
}
if (numbers[i] < small) {
small = numbers[i]
}
i = i + 1
}
print("Maximum Number ====================\(largest)")// 809
print("Minimum Number ====================\(small)")// 116
}
With Swift 1.2 (and maybe earlier) you now need to use:
let nums = [1, 6, 3, 9, 4, 6];
let numMax = nums.reduce(Int.min, combine: { max($0, $1) })
For working with Double values I used something like this:
let nums = [1.3, 6.2, 3.6, 9.7, 4.9, 6.3];
let numMax = nums.reduce(-Double.infinity, combine: { max($0, $1) })
In Swift 2.0, the minElement and maxElement become methods of SequenceType protocol, you should call them like:
let a = [1, 2, 3]
print(a.maxElement()) //3
print(a.minElement()) //1
Using maxElement as a function like maxElement(a) is unavailable now.
The syntax of Swift is in flux, so I can just confirm this in Xcode version7 beta6.
It may be modified in the future, so I suggest that you'd better check the doc before you use these methods.
Here's a performance test for the solutions posted here. https://github.com/tedgonzalez/MaxElementInCollectionPerformance
This is the fastest for Swift 5
array.max()
var numbers = [1, 2, 7, 5];
var val = sort(numbers){$0 > $1}[0];
Apple's Swift Algorithms introduced 2021 contains Minima and/or Maxima which is likely highly optimized.
Example from the documentation:
let numbers = [7, 1, 6, 2, 8, 3, 9]
if let (smallest, largest) = numbers.minAndMax(by: <) {
// Work with 1 and 9....
}
The total complexity is O(k log k + nk), which will result in a runtime close to O(n) if k is a small amount. If k is a large amount (more than 10% of the collection), we fall back to sorting the entire array. Realistically, this means the worst case is actually O(n log n).
Updated for Swift 3/4:
Use below simple lines of code to find the max from array;
var num = [11, 2, 7, 5, 21]
var result = num.sorted(){
$0 > $1
}
print("max from result: \(result[0])") // 21
Just curious why you think the way it was taught in school is potentially expensive? You're running a for loop which has the time complexity of O(N). That's actually better than most sorting algorithms and equivalent to the performance of higher-order methods like reduce.
So I would think that in terms of performance, a for loop is as good as it gets. I don't think you'll find anything better than O(N) for finding max.
Of course, just use the .max() method provided by apple is the way to go.
If both minimum and maximum values are desired, an efficient approach could be to use a single reduce operation with a tuple:
let values = [11, 2, 7, 5, 21]
let (minimum, maximum) = values.reduce((Int.max, Int.min)) {
(min($0.0, $1), max($0.1, $1))
}
print(minimum, maximum) // 2, 21
let array: [Int] = [2, -22, -1, -5600, 333, -167]
var min = 0
var max = array[0]
for i in array {
// finding the min
if min > i {
min = i
}
// finding the max
if max < i {
max = i
}
}
print("Minimum: \(min)\nMaximum: \(max)")
You can also sort your array and then use array.first or array.last

Resources