Array modification in loop - arrays

I'm working on a command-line application. The first array (which is called firstArray, yes) is a result of user input via readLine(), all of its elements is Double. Now I have to create a second array with results of calculations applied to my first array. Some of results is NaN, cause of trigonometric calculations. I need to change all the NaNs to string, but I get the error "Cannot assign value of type 'String' to type 'Double'". How to solve this problem?
func calcLn () -> [Double] {
var calculatedArray = [Double]()
for item in firstArray {
var result = log(Double((-100))/(cos(item)))
calculatedArray.append(result)
}
for index in 0..<calculatedArray.count {
if calculatedArray[index].isNaN {
calculatedArray[index] = String("can't calculate")

An array can only store one type of stuff. calculatedArray can only store Doubles, so you can't set its elements to Strings.
You can create a new array called outputArray that can store strings, and convert all the doubles to strings:
var outputArray = [String]()
for index in 0..<calculatedArray.count {
if calculatedArray[index].isNaN {
outputArray.append("can't calculate")
} else {
outputArray.append("\(calculatedArray[index])")
}
}
Your calcLn method returns a [Double], but it seems like you want to return outputArray. If that's the case, you need to change its signature to return [String].
Note that you can do array transformations with map. Here is a shorter version of your code:
func calcLn () -> [String] {
let calculatedArray = firstArray.map { log(100.0/cos($0)) }
let outputStringsArray = calculatedArray.map { $0.isNaN ? "can't calculate" : "\($0)" }
return outputStringsArray
}

Related

Swift: sort an array of strings...of more or less numbers

I have an array of strings, examples are as follows:
"0.125-0.25"
"1-2"
"50-100"
"100-200"
The result of sorting these is:
"0.125-0.25"
"1-2"
"100-200"
"50-100"
And if I append("1000-2000") to the array and then sort it will be:
"0.125-0.25"
"1-2"
"100-200"
"1000-2000"
"50-100"
But what I want is:
"0.125-0.25"
"1-2"
"50-100"
"100-200"
"1000-2000"
It's definitely an edge case, but I have been having luck on my own. Thanks everyone.
A working but not very efficient solution is to extract the first Double value in the string ranges and sort by them. It's very inefficient because in each call of the closure both Double values have to be recreated.
var array = ["1-2", "50-100", "0.125-0.25", "100-200"]
array.append("1000-2000")
let sortedArray = array.sorted { (str1, str2) -> Bool in
func firstDouble(of string: String) -> Double { return Double(string.components(separatedBy: "-").first!)! }
return firstDouble(of: str1) < firstDouble(of: str2)
}
print(sortedArray)
A more efficient solution is to map the array (once) to its first Double value, then zip both arrays, sort the combined array by the Double array and map the result back to the string-range array.
var array = ["1-2", "50-100", "0.125-0.25", "100-200"]
array.append("1000-2000")
let firstDoubleArray = array.map{Double($0.components(separatedBy: "-").first!)!}
let sortedArray = zip(array, firstDoubleArray).sorted {$0.1 < $1.1}.map{$0.0}
print(sortedArray)
What it appears you're sorting is ranges of Doubles, so the problem can be clarified by creating an intermediate object…
struct DoubleRange: Comparable {
let start: Double
let end: Double
init(string: String) {
let components = string.split(separator: "-")
start = Double(components[0])! // Be careful with `!` here, I'm assuming the format is always correct
end = Double(components[1])!
}
var stringValue: String {
return "\(start)-\(end)"
}
static func < (lhs: DoubleRange, rhs: DoubleRange) -> Bool {
return lhs.start < rhs.start
}
}
Then sorting is simple…
var array = ["1-2", "50-100", "0.125-0.25", "100-200"]
array.append("1000-2000")
array.map(DoubleRange.init).sorted().map{$0.stringValue}
// ["0.125-0.25", "1.0-2.0", "50.0-100.0", "100.0-200.0", "1000.0-2000.0"]
And if you always want to convert back to the string value, you could add…
extension Array where Element == String {
func sortedDoubleRange() -> [String] {
return array.map(DoubleRange.init).sorted().map{$0.stringValue}
}
}
array.sortedDoubleRange()
Be careful with this though… it will crash if any of strings are formatted incorrectly.

Convert a 2d array of strings to a 2d array of double swift

I have 2 arrays:
var locationString = [[String]]()
var doubleArray = [[Double]]()
The array data is appended after a parser has ran just in case you are wondering why there is no data.
Essentially I am trying to convert the locationString from string to double.
I originally tried the following:
let doubleArray = locationString.map{ Double($0) }
but this does not seem to work as i get an error of:
Cannot invoke initializer for type 'Double' with an argument list of type ((String]))
Any help would be appreciated, thanks.
Use map with compactMap map:
let doubleArray = locationString.map { $0.compactMap(Double.init) }
Example:
let locationString = [["1.2", "2.3"], ["3.4", "4.4", "hello"]]
let doubleArray = locationString.map { $0.compactMap(Double.init) }
print(doubleArray) // [[1.2, 2.3], [3.4, 4.4]]
The outer map processes each array of strings. The inner compactMap converts the Strings to Double and drops them if the conversion returns nil because the String is not a valid Double.
To trim leading and trailing whitespace in your Strings before converting to Double, use .trimmingCharacters(in: .whitespaces):
let doubleArray = locationString.map { $0.compactMap { Double($0.trimmingCharacters(in: .whitespaces )) } }

Simple way to convert an array of non-optionals to an array of optionals

I wish to assign an array [T] to an optional array [T?]. This seems like it should be straightforward but the only solution I came up with is to do it manually.
struct ArrayHelper<T> {
func toArrayOfOptionals(input: [T]) -> [T?] {
var result = [T?]()
for value in input {
result.append(value)
}
return result
}
}
I don't think there are any built-in ways to do this seamlessly, but map ought to be a simpler solution:
var input = [T]()
let output = input.map { Optional($0) }
Edit: Code modified based on suggestions in comments.

How to get an array having unique ranges from the array with duplicated ranges?

I can get an array of unique numbers from the array having duplicated numbers
let arrayWithReapeats = [1, 2, 3, 7, 3]
let unique = Array(Set(arrayWithReapeats))
I need an array having unique ranges
Range<String.Index>
from the array having duplicated ranges for instance like this.
let arrayWithReapeatsIdexes = [1..<5, 3..<9, 9..<25, 3..<9]
I cannot use the same approach with Set since only String, Int, Double, and Bool are hashable by default. How to make ranges hashable to be able to use the approach above?
The only requirement for the hash value is
x == y implies x.hashValue == y.hashValue
which means that the "trivial" hash function
extension Range : Hashable {
public var hashValue: Int {
return 0
}
}
is valid and works:
let arrayWithRepeatingIndexes = [1..<5, 3..<9, 9..<25, 3..<9]
let arrayWithUniqueIndexes = Array(Set(arrayWithRepeatingIndexes))
print(arrayWithUniqueIndexes)
// [Range(1..<5), Range(3..<9), Range(9..<25)]
You can also use the fact that the distance from start to end
index is a integer type (and thus has a hash value):
public var hashValue: Int {
return startIndex.distanceTo(endIndex).hashValue
}
or compute the hash value from the description string (such as "3..<9"):
public var hashValue: Int {
return description.hashValue
}
You'll have to figure out which one is the most effective for your purpose.
try this:
extension SequenceType where Generator.Element: Equatable {
func unique() -> [Generator.Element] {
var seen: Array<Generator.Element> = []
return filter {
if seen.contains($0){
return false
} else {
seen.append($0)
return true
}
}
}
}

Passing a string parameter to a func to access a property of an array

I am writing a data gathering and manipulation program in Swift (my first time trying to program in Swift).
I have a function (determineHeighestColumnValue) to which I pass two parameters; an array containing dictionary objects loaded from a core data persistent store and a string representing the key for property that I want to access from a dictionary object at a particular index in that array.
Each dictionary object looks similar to this:
{
debtorDays = "-";
debtors = "-";
eacFees = 284680;
eacToDateContribution = 117159;
eacToDateContributionPerFees = "41%";
eacToDateOtherCosts = 6985;
eacToDateReimburseable = 10640;
eacToDateSalary = 171176;
lastInvoice = NA;
lastRevisionDate = "11-Jun-15";
etc etc
I am trying to work out how I can pass the key as a string and then use that to access the associated array value through this piece of code - "pprFiles[index].item.toDouble()" in the if statement below. ".toDouble()" is a string extension that returns the double value of the string. The function is determining column heights so the values passed and being accessed in the dictionary object are all number values as Strings - hence the conversion to a Double.
When I run the code with the "item" parameter specifically typed as a key then the code works fine. However, as a passed parameter I get a compiler error on the if statement.
Any thoughts on how I can pass a string value and get the if statement to work would be gratefully received.
The function code is:
func determineHeighestColumnValue(pprFiles: Array<PPRRowData>, item: String) ->Array<Double>{
var tempArray: [Double] = []
let count = pprFiles.count
for var index = 0; index < count; index++ {
// ******* need to work out how to get the reference right in the next line for item to be index.item
if pprFiles[index].item.toDouble() != nil {
tempArray.append(item.toDouble()!)
} else {
tempArray.append(0)
}
}
let highestColumn = maxElement(tempArray.map({abs($0)}))
if highestColumn != 0 {
tempArray = tempArray.map({$0 / highestColumn})
} else {
tempArray = tempArray.map({$0 * 0})
}
return tempArray
}
You can use Key-Value Coding with Core Data managed objects:
if let val = pprFiles[index].valueForKey(item) as? String {
// ...
}

Resources