align left and right in the same line swift - swift

I want to align texts left and right on the same line in swift. For example, I have a string with product names to the left and the price to the right. Both on the same line. Is this possible?
I need this for bluetooth printing, where every line has exactly 32 characters.

If I understand correctly, you want something like this:
func alignLeftAndRight(left: String, right: String, length: Int) -> String {
// calculate how many spaces are needed
let numberOfSpacesToAdd = length - left.count - right.count
// create those spaces
let spaces = Array(repeating: " ", count: numberOfSpacesToAdd < 0 ? 0 : numberOfSpacesToAdd).joined()
// join these three things together
return left + spaces + right
}
Usage:
print(alignLeftAndRight(left: "Product", right: "Price", length: 32))
print(alignLeftAndRight(left: "Foo", right: "1", length: 32))
print(alignLeftAndRight(left: "Product", right: "123", length: 32))
print(alignLeftAndRight(left: "Something", right: "44", length: 32))
print(alignLeftAndRight(left: "Hello", right: "7777", length: 32))
Output:
Product Price
Foo 1
Product 123
Something 44
Hello 7777

Related

Efficient way to get a subsequence with a precondition in Swift

I have an ordered sequence of numbers, let's say something like
0, 1, 2, 3, 5, 6, 11, 12, 15, 20
Given a number N, how could I get a sequence that starts from the last number that is smaller than N? For example, if N = 7, I'd like to get back
6, 11, 12, 15, 20
Please note that this sequence will get very big and new numbers will be appended.
drop(while:) seemed like a good candidate, but in the example above it would also drop 6 so I can't use it.
For huge sorted arrays the most efficient way is binary search. It cuts the array in half until the index was found.
extension RandomAccessCollection where Element : Comparable {
func lastIndex(before value: Element) -> Index {
var slice : SubSequence = self[...]
while !slice.isEmpty {
let middle = slice.index(slice.startIndex, offsetBy: slice.count / 2)
if value < slice[middle] {
slice = slice[..<middle]
} else {
slice = slice[index(after: middle)...]
}
}
return slice.startIndex == self.startIndex ? startIndex : index(before: slice.startIndex)
}
}
let array = [0, 1, 2, 3, 5, 6, 11, 12, 15, 20]
let index = array.lastIndex(before: 7)
print(array[index...])

swift - how to print to console multi line Strings in 2 distinct columns on the screen

I have 2 very long strings which span multiple lines each and want to print to console both strings in their own "column" to the terminal
i.e.
let veryLongStringWithNewLines = "a very long string with \n
and blah blah \n
and more text ....."
let anotherVeryLongStringWithNewLines = "......."
print ("\(veryLongStringWithNewLines) %???Break Screen in Center???% \(anotherVeryLongStringWithNewLines)") // <<<< TO THE CONSOLE
I want to divide the console into 2 columns such that each string is printed in its own area , but side by side , i.e. EXCEL with 2 columns, each string in its own column
The string should wrap inside of that column to new lines when necessary
Not sure how to achieve this
Here's something to get you started:
// Break a string up into an array of Strings, first on newlines
// and then by width if the lines are longer than width
func breakIntoLines(text: String, width: Int) -> [String] {
var result = [String]()
for line in text.split(separator: "\n") {
var str = String(line)
while str.count > width {
result.append(String(str.prefix(width)))
str = String(str.dropFirst(width))
}
// pad last line to width to make displaying easier
result.append(str + String(repeating: " ", count: width - str.count))
}
return result
}
// print two Strings in two columns optionally keeping the rows
// in sync
func printIn2Columns(text1: String, text2: String, columnWidth: Int, space: Int, keepRowsInSync: Bool = false) {
if keepRowsInSync {
// split the lines into rows on newline
var rows1 = text1.split(separator: "\n")
var rows2 = text2.split(separator: "\n")
// pad the shorter number of rows
if rows1.count > rows2.count {
rows2 += Array(repeating: "", count: rows1.count - rows2.count)
} else if rows2.count > rows1.count {
rows1 += Array(repeating: "", count: rows2.count - rows1.count)
}
// print each row in two columns
for (row1, row2) in zip(rows1, rows2) {
printIn2Columns(text1: String(row1), text2: String(row2), columnWidth: columnWidth, space: space)
}
} else {
var column1 = breakIntoLines(text: text1, width: columnWidth)
var column2 = breakIntoLines(text: text2, width: columnWidth)
// pad the shorter column with extra rows
let blankLine = String(repeating: " ", count: columnWidth)
if column1.count > column2.count {
column2 += Array(repeating: blankLine, count: column1.count - column2.count)
} else if column2.count > column1.count {
column1 += Array(repeating: blankLine, count: column2.count - column1.count)
}
let spacing = String(repeating: " ", count: space)
for (line1, line2) in zip(column1, column2) {
print("\(line1)\(spacing)\(line2)")
}
}
}
Tests:
let text1 = """
This is a test
of the code which
breaks this up into
columns
"""
let text2 = """
Well, here goes nothing!
Does this do what you want?
"""
printIn2Columns(text1: text1, text2: text2, columnWidth: 8, space: 5)
This is Well, he
a test re goes
of the c nothing!
ode whic Does thi
h s do wha
breaks t t you wa
his up i nt?
nto
columns
printIn2Columns(text1: text2, text2: text1, columnWidth: 10, space: 4)
Well, here This is a
goes noth test
ing! of the cod
Does this e which
do what yo breaks thi
u want? s up into
columns
printIn2Columns(text1: text2, text2: text1, columnWidth: 30, space: 5)
Well, here goes nothing! This is a test
Does this do what you want? of the code which
breaks this up into
columns
Keeping the rows in sync
If you are comparing two texts, it might be desirable to keep the rows in sync. If you have to wrap a row in one column but not the other, add blank lines to the shorter to keep the rows of the original texts in sync.
let t1 = """
1:
2:
3: this is a really long line 3
4:
5: this is a really long line 5
6:
"""
let t2 = """
one - this is a really long line one
two
three - this is a really long line three
four
five
six
"""
printIn2Columns(text1: t1, text2: t2, columnWidth: 16, space: 5, keepRowsInSync: true)
1: one - this is a
really long line
one
2: two
3: this is a rea three - this is
lly long line 3 a really long li
ne three
4: four
5: this is a rea five
lly long line 5
6: six

Without debug mode UnsafePointer withMemoryRebound will gives wrong value

Here I am trying to concatenate 5 bytes into the single Integer value, I am getting an issue with UnsafePointer withMemoryRebound method.
when I am debugging and checking logs it will gives the correct value. But when I try without debug, it will give the wrong value.(4 out of 5 times wrong value). I got confuses on this API. Is it correct way I am using?
case 1:
let data = [UInt8](rowData) // rowData is type of Data class
let totalKM_BitsArray = [data[8],data[7],data[6],data[5],data[4]]
self.totalKm = UnsafePointer(totalKM_BitsArray).withMemoryRebound(to:UInt64.self, capacity: 1) {$0.pointee}
case 2:
Below code will work for both Enable or Disable debug mode And gives the correct value.
let byte0 : UInt64 = UInt64(data[4])<<64
let byte1 : UInt64 = UInt64(data[5])<<32
let byte2 : UInt64 = UInt64(data[6])<<16
let byte3 : UInt64 = UInt64(data[7])<<8
let byte4 : UInt64 = UInt64(data[8])
self.totalKm = byte0 | byte1 | byte2 | byte3 | byte4
Please suggest me UnsafePointer way of using? Why will this issue come?
Addtional infomation :
let totalKm : UInt64
let data = [UInt8](rowData) // data contain [100, 200, 28, 155, 0, 0, 0, 26, 244, 0, 0, 0, 45, 69, 0, 0, 0, 4, 246]
let totalKM_BitsArray = [data[8],data[7],data[6],data[5],data[4]] // contain [ 244,26,0,0,0]
self.totalKm = UnsafePointer(totalKM_BitsArray).withMemoryRebound(to:UInt64.self, capacity: 1) {$0.pointee}
// when print log gives correct value, when run on device give wrong 3544649566089386 like this.
self.totalKm = byte0 | byte1 | byte2 | byte3 | byte4
// output is 6900 This is correct as expected
There are a few problems with this approach:
let data = [UInt8](rowData) // rowData is type of Data class
let totalKM_BitsArray = [data[8], data[7], data[6], data[5], data[4]]
self.totalKm = UnsafePointer(totalKM_BitsArray)
.withMemoryRebound(to:UInt64.self, capacity: 1) { $0.pointee }
Dereferencing UnsafePointer(totalKM_BitsArray) is undefined behaviour, as the pointer to totalKM_BitsArray's buffer is only temporarily valid for the duration of the initialiser call (hopefully at some point in the future Swift will warn on such constructs).
You're trying to bind only 5 instances of UInt8 to UInt64, so the remaining 3 instances will be garbage.
You can only withMemoryRebound(_:) between types of the same size and stride; which is not the case for UInt8 and UInt64.
It's dependant on the endianness of your platform; data[8] will be the least significant byte on a little endian platform, but the most significant byte on a big endian platform.
Your implementation with bit shifting avoids all of these problems (and is generally the safer way to go as you don't have to consider things like layout compatibility, alignment, and pointer aliasing).
However, assuming that you just wanted to pad out your data with zeroes for the most significant bytes, with rowData[4] to rowData[8] making up the rest of the less significant bytes, then you'll want your bit-shifting implementation to look like this:
let rowData = Data([
100, 200, 28, 155, 0, 0, 0, 26, 244, 0, 0, 0, 45, 69, 0, 0, 0, 4, 246
])
let byte0 = UInt64(rowData[4]) << 32
let byte1 = UInt64(rowData[5]) << 24
let byte2 = UInt64(rowData[6]) << 16
let byte3 = UInt64(rowData[7]) << 8
let byte4 = UInt64(rowData[8])
let totalKm = byte0 | byte1 | byte2 | byte3 | byte4
print(totalKm) // 6900
or, iteratively:
var totalKm: UInt64 = 0
for byte in rowData[4 ... 8] {
totalKm = (totalKm << 8) | UInt64(byte)
}
print(totalKm) // 6900
or, using reduce(_:_:):
let totalKm = rowData[4 ... 8].reduce(0 as UInt64) { accum, byte in
(accum << 8) | UInt64(byte)
}
print(totalKm) // 6900
We can even abstract this into an extension on Data in order to make it easier to load such fixed width integers:
enum Endianness {
case big, little
}
extension Data {
/// Loads the type `I` from the buffer. If there aren't enough bytes to
/// represent `I`, the most significant bits are padded with zeros.
func load<I : FixedWidthInteger>(
fromByteOffset offset: Int = 0, as type: I.Type, endianness: Endianness = .big
) -> I {
let (wholeBytes, spareBits) = I.bitWidth.quotientAndRemainder(dividingBy: 8)
let bytesToRead = Swift.min(count, spareBits == 0 ? wholeBytes : wholeBytes + 1)
let range = startIndex + offset ..< startIndex + offset + bytesToRead
let bytes: Data
switch endianness {
case .big:
bytes = self[range]
case .little:
bytes = Data(self[range].reversed())
}
return bytes.reduce(0) { accum, byte in
(accum << 8) | I(byte)
}
}
}
We're doing a bit of extra work here in order to we read the right number of bytes, as well as being able to handle both big and little endian. But now that we've written it, we can simply write:
let totalKm = rowData[4 ... 8].load(as: UInt64.self)
print(totalKm) // 6900
Note that so far I've assumed that the Data you're getting is zero-indexed. This is safe for the above examples, but isn't necessarily safe depending on where the data is coming from (as it could be a slice). You should be able to do Data(someUnknownDataValue) in order to get a zero-indexed data value that you can work with, although unfortunately I don't believe there's any documentation that guarantees this.
In order to ensure you're correctly indexing an arbitrary Data value, you can define the following extension in order to perform the correct offsetting in the case where you're dealing with a slice:
extension Data {
subscript(offset offset: Int) -> Element {
get { return self[startIndex + offset] }
set { self[startIndex + offset] = newValue }
}
subscript<R : RangeExpression>(
offset range: R
) -> SubSequence where R.Bound == Index {
get {
let concreteRange = range.relative(to: self)
return self[startIndex + concreteRange.lowerBound ..<
startIndex + concreteRange.upperBound]
}
set {
let concreteRange = range.relative(to: self)
self[startIndex + concreteRange.lowerBound ..<
startIndex + concreteRange.upperBound] = newValue
}
}
}
Which you can use then call as e.g data[offset: 4] or data[offset: 4 ... 8].load(as: UInt64.self).
Finally it's worth noting that while you could probably implement this as a re-interpretation of bits by using Data's withUnsafeBytes(_:) method:
let rowData = Data([
100, 200, 28, 155, 0, 0, 0, 26, 244, 0, 0, 0, 45, 69, 0, 0, 0, 4, 246
])
let kmData = Data([0, 0, 0] + rowData[4 ... 8])
let totalKm = kmData.withUnsafeBytes { buffer in
UInt64(bigEndian: buffer.load(as: UInt64.self))
}
print(totalKm) // 6900
This is relying on Data's buffer being 64-bit aligned, which isn't guaranteed. You'll get a runtime error for attempting to load a misaligned value, for example:
let data = Data([0x01, 0x02, 0x03])
let i = data[1...].withUnsafeBytes { buffer in
buffer.load(as: UInt16.self) // Fatal error: load from misaligned raw pointer
}
By loading individual UInt8 values instead and performing bit shifting, we can avoid such alignment issues (however if/when UnsafeMutableRawPointer supports unaligned loads, this will no longer be an issue).

swift 3 alphanumeric sorting re: I, II, III, IV, IX, V,

Curious to know if anyone can offer a solution to sorting roman numerals (string type) I through X. When I sort an array using {$0.compare ($1, options: .numeric) == .orderedAscending}, I get I, II, III, IV, IX, V, VI, VII, VIII X. As you can see, IX follows IV because of the "I."
By the way, the data model is a dictionary [String:[String:[String]]] The Bold indicates where in the dictionary the data to be sorted exists.
Is this what you mean? Perhaps by converting them first
let romanValues = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]
let arabicValues = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]
var romanValue = ""
var startingValue = number
for (index, romanChar) in enumerate(romanValues) {
var arabicValue = arabicValues[index]
var div = startingValue / arabicValue
if (div > 0)
{
for j in 0..<div
{
//println("Should add \(romanChar) to string")
romanValue += romanChar
}
startingValue -= arabicValue * div
}
}
return romanValue
I came up with a simple solution. Rather than hassle with the key of the dictionary to populate the rows of a table view in the desired numeric order, I created a simple array- which is ordered. When a row is selected, I can use didSelectRow to identify the indexPath and the related string of the array- for example row 1 = "Article I". I can then pass the selected string value "Article I" as a variable to use in the selection of the identical key [String:[String:[String]]] within the nested dictionary.
PS - the solution posted by Lucas appears to be a partial copy and paste of a function that can be found on GitHub. It appears Lucas inadvertently failed to copy and paste the entire function.

Simple Swift Fibonacci program crashing (Project Euler 2)

I am trying to solve the second problem on Project Euler. The problem is as follows:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
I think I've written a solution, but when I try to run my code it crashes my Swift playground and gives me this error message:
Playground execution aborted: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
var prev = 0
var next = 1
var num = 0
var sum = 0
for var i = 1; i < 400; i++ {
num = prev + next
if next % 2 == 0 {
sum += next
}
prev = next
next = num
}
print(sum)
The weird thing is, if I set the counter on my loop to less than 93, it works fine. Explicitly setting the variable names to Double does not help. Anyone know what's going on here?
There is nothing weird about this at all. Do you know how large the 400 fibonacci number is?
176023680645013966468226945392411250770384383304492191886725992896575345044216019675
Swift Int64 or UInt64 simply cannot handle that large of a number. The later can go up to 18446744073709551615 at max - not even close.
If you change your variables to be doubles it works but will be inaccurate:
var prev : Double = 0
var next : Double = 1
var num : Double = 0
var sum : Double = 0
will yield
2.84812298108489e+83
which is kind of close to the actual value of
1.76e+83
Luckily you do not need to get values that big. I would recommend not writing a for loop but a while loop that calculates the next fibonacci number until the break condition is met whose values do not exceed four million.
The Fibonacci numbers become very large quickly. To compute large Fibonacci numbers, you need to implement some kind of BigNum. Here is a version the makes a BigNum that is implemented internally as an array of digits. For example, 12345 is implemented internally as [1, 2, 3, 4, 5]. This makes it easy to represent arbitrarily large numbers.
Addition is implemented by making the two arrays the same size, then map is used to add the elements, finally the carryAll function restores the array to single digits.
For example 12345 + 67:
[1, 2, 3, 4, 5] + [6, 7] // numbers represented as arrays
[1, 2, 3, 4, 5] + [0, 0, 0, 6, 7] // pad the shorter array with 0's
[1, 2, 3, 10, 12] // add the arrays element-wise
[1, 2, 4, 1, 2] // perform carry operation
Here is the implementation of BigNum. It is also CustomStringConvertible which makes it possible to print the result as a String.
struct BigNum: CustomStringConvertible {
var arr = [Int]()
// Return BigNum value as a String so it can be printed
var description: String { return arr.map(String.init).joined() }
init(_ arr: [Int]) {
self.arr = carryAll(arr)
}
// Allow BigNum to be initialized with an `Int`
init(_ i: Int = 0) {
self.init([i])
}
// Perform the carry operation to restore the array to single
// digits
func carryAll(_ arr: [Int]) -> [Int] {
var result = [Int]()
var carry = 0
for val in arr.reversed() {
let total = val + carry
let digit = total % 10
carry = total / 10
result.append(digit)
}
while carry > 0 {
let digit = carry % 10
carry = carry / 10
result.append(digit)
}
return result.reversed()
}
// Enable two BigNums to be added with +
static func +(_ lhs: BigNum, _ rhs: BigNum) -> BigNum {
var arr1 = lhs.arr
var arr2 = rhs.arr
let diff = arr1.count - arr2.count
// Pad the arrays to the same length
if diff < 0 {
arr1 = Array(repeating: 0, count: -diff) + arr1
} else if diff > 0 {
arr2 = Array(repeating: 0, count: diff) + arr2
}
return BigNum(zip(arr1, arr2).map { $0 + $1 })
}
}
// This function is based upon this question:
// https://stackoverflow.com/q/52975875/1630618
func fibonacci(to n: Int) {
guard n >= 2 else { return }
var array = [BigNum(0), BigNum(1)]
for i in 2...n {
array.append(BigNum())
array[i] = array[i - 1] + array[i - 2]
print(array[i])
}
}
fibonacci(to: 400)
Output:
1
2
3
5
8
...
67235063181538321178464953103361505925388677826679492786974790147181418684399715449
108788617463475645289761992289049744844995705477812699099751202749393926359816304226
176023680645013966468226945392411250770384383304492191886725992896575345044216019675