Getting Over Struct Implementation in Swift - arrays

In Swift, everything is implemented as a struct rather than a class. Values are being passed in, but the memory address does not store them. Here is an example:
import UIKit
var array = Array<Int>()
array = [6,2,9,1,10,4,9,3,5,8,7]
let count = array.count
func insertSort(var arr : Array<Int>)->(){
for(var i = 1; i<arr.count-1; i++){
var j : Int
for( j = i; j > 0; j--){
if(arr[j]<arr[j-1]){
var temp = arr[j-1]
var temp2 = arr[j]
arr.removeAtIndex(j-1)
arr.insert(temp2, atIndex: j-1)
arr.removeAtIndex(j)
arr.insert(temp, atIndex: j)
}
}
}
for item in arr{
print(item)
}
}
insertSort(array)
array
I know that this isn't the most concise way to implement an insertion sort, but I was just trying to use the most Swift I could.
My issue: through the print statement in the function, I can see that the algorithm works - the list is returned sorted. However, when I print the array at the bottom, Playground returns the same array as the one I declared at the top, ie unsorted. I know why that is (the array is not implemented as a class), I just wanted to know if there is a way to fix it.

To modify a value type passed to a function, you need to pass it as an inout parameter:
func insertSort(inout arr: [Int]) {
// etc.
}
insertSort(&array)
This is how Swift.sort is declared – try cmd-opt-clicking it in a playground or take a look at the Swifter docs.
inout should be used sparingly – one of the big benefits of structs is that they can be declared immutable with let, but immutable structs cannot be passed as inout parameters. This is why the standard library declares both sort, which takes an inout and sorts in-place, and sorted, which takes input by value and returns a freshly sorted array.

Related

Multidimensional-array in Ceylon

I would like to work in Ceylon with a multidimensional array. Is this planned in Ceylon? If so, how can I declare it?
I would like to use this construct in Ceylon, as shown here in Java:
int x = 5;
int y = 5;
String[][] myStringArray = new String [x][y];
myStringArray[2][2] = "a string";
First, consider whether you really need an array (i.e. something with fixed length and modifiable elements), or whether a list (or list of lists) or a map might be better. Though from your example, you seem to need modification.
In the JVM, a "multidimensional" array is just an array of arrays.
In Java, new String[y] creates an array filled with null entries, which is not an allowed value of type String in Ceylon. So you can either have an array of String? (which allows null), or pre-fill your array with some other value, using e.g. Array.ofSize(...):
Array.ofSize(y, "hello")
The same is valid for arrays of arrays. We could do this:
value myStringArray = Array.ofSize(x, Array.ofSize(y, "hello"));
Though this would have the same array in each "row" of the 2D-array, which is not what we want (as replacing myStringArray[2][2] would replace all entries with a 2 as the second coordinate). Here the other Array constructor is useful, which takes an iterable:
value myStringArray = Array({ Array.ofSize(y, "hello") }.repeat(x));
This takes advantage of the fact that the iterable enumeration evaluates its arguments lazily, and thus the array constructor will get x different elements.
I like Paulo's answer, but here's an alternative approach, which allows us to use a comprehension to populate the 2D array:
//the size of the square 2D array
value n = 5;
//create it using a nested comprehension
value arr = Array {
for (i in 1..n-1) Array {
for (j in 0..n-1)
i==j then 1 else 0
}
};
//display it
for (row in arr) {
printAll(row);
}

Generic type array do not take empty array as input

import Foundation
func insertionSort<T where T: Comparable>(var items:[T])-> [T] {
for (index, _) in items.enumerate().dropFirst() {
var j = index
while ((j > 0) && (items[j] < items[j-1])) {
swap(&items[j], &items[j-1])
j = j-1
}
}
return items
}
// Test the function
insertionSort([]) // Generic type array is not taking empty array
When I am trying to call insertionSort with empty array, I get
Cannot invoke 'insertionSort' with an argument list of type '([_])'
I am not able to figure out how to fix this.
To call generic functions in Swift, Swift needs to be able to infer the generic parameters.
One way giving the type information to Swift, is using an intermediate variable.
(Like noted in Lu_'s comment.)
let arr: [Int] = []
let result = insertionSort(arr)
Another way is using as.
let result = insertionSort([] as [Int])
(Remember, var parameter does not modify the actual argument. It just makes a mutable copy, but does not write it back to the original argument. Swift 3 removed var parameters, as it's so confusing. You may need to assign the return value of the function to a variable.)

Xtend: Add element to array in for-loop

I am trying to do the simplest operation in Xtend, but don't know how. I want to add an double value to an double[] array inside a for-loop.
For example:
def do(EList<MyObject> list) {
var double[] array = newDoubleArrayOfSize(list.size);
for (i : 0 ..< list.size) {
array[i] = list.get(i).myValue;
}
return array;
}
The forth line shows an error, because I can't use array[i] = ....
How do I implement that in Xtend? Haven't found anything in the user guide.
Xtend has a different ("list-like") syntax for accessing array elements, see the related documentation for details:
Retrieving and setting values of arrays is done through the extension
methods get(int) and set(int, T) which are specifically overloaded for
arrays and are translated directly to the equivalent native Java code
myArray[int].
So your code should be:
def method(EList<MyObject> list) {
var double[] array = newDoubleArrayOfSize(list.size);
for (i : 0 ..< list.size) {
array.set(i, list.get(i).myValue);
}
return array;
}
You can further simplify your method by omitting semicolons and the type declaration of the array variable:
def method(EList<MyObject> list) {
val array = newDoubleArrayOfSize(list.size)
for (i : 0 ..< list.size) {
array.set(i, list.get(i).myValue)
}
return array
}
Another alternative is to write your method in a more functional style. If you can replace EList with List (or EList extends/implements List) then you could simply write:
def double[] method(List<MyObject> list) {
list.map[myValue]
}
In this case you must explicitly declare the return type as double[] because otherwise it would be inferred as List<Double>.
(Just one more thing: usually collections are preferred over arrays because they are more flexible and have more rich APIs, and Xtend has some additional goodies as well like collection literals.)

Append to an array from another function?

I have this code in which I am appending to an array of a struct in one function. The change does not appear in the other function.
type my struct{
arr []int
}
func New_my() *my {
m := new (my)
return m
}
func (m my) Dosomething(){
m.arr = append(m.arr,1)
m.arr = append(m.arr,2)
m.arr = append(m.arr,3)
}
func (m my) Dosomethingelse(){
fmt.Println(m.arr)
}
func main(){
m:= New_my()
m.Dosomething()
m.Dosomethingelse()
}
The output is:
[]
Please, explain what is happening? Why does the change not appear in the array?
If you are new to go you should totally do the tour of go and the effective go document. Go is a new language and with a strange combination of ideas so the official documentation is the best place to start.
First of all you are using a slice not an array. (Read this to understand slices)
The error in your code is because Dosomething() is defined for my instead of *my. This is explained here.
Just change it to:
func (m *my) Dosomething(){
m.arr = append(m.arr,1)
m.arr = append(m.arr,2)
m.arr = append(m.arr,3)
}
In go everything is passed by value so in your code you are passing a copy of the struct to the function Dosomething(), and because the capacity of the slice is 0, the append function creates a new underlying array and returns a reference to it, and when yo do:
m.arr = append(...)
the new slice (using the new array) is lost because it is stored in m that is a copy of the original struct, if m were a *my the new slice would replace the previous in the arr property.
In Go everything is passed by value, including the this/self/me/m argument provided to receivers (aka methods).
In Go if something does not appear to be passed by value, then either a pointer to it, or a struct containing a pointer (as is the case for string, slice, etc) is being passed.
That means right now your DoSomething gets a copy of the self-object and appends to that.
So in this case Topo is correct, you just need to change DoSomething() to pass its self/this/m argument as a pointer.
func (m *my) Dosomething(){
m.arr = append(m.arr,1)
m.arr = append(m.arr,2)
m.arr = append(m.arr,3)
}
I assume this is toy code, but a couple of notes:
You could write this more efficiently as:
func (m *my) Dosomething(){
m.arr = append(m.arr,[]int{1,2,3}...)
}
And it would be more idiomatic to rename New_my() to newMy()

Swift Generic Array 'not identical' error

I'm just going through some Swift tuts that are obviously already outdated as of Beta3 ...
func exchange<T>(data:[T], i:Int, j:Int)
{
let temp = data[i];
data[i] = data[j];
data[j] = temp;
}
Playgrounds tells me:
Error: #lvalue $T8 is not identical to T.
How do I change it to make it work?
Arrays in Swift are value types. That means that data is copied when passed into your exchange method, but you are trying to modify the copy to affect the original version. Instead you should do one of two things:
1. Define data as an inout parameter:
func exchange<T>(inout data:[T], i:Int, j:Int)
Then when calling it you have to add an & before the call:
var myArray = ["first", "second"]
exchange(&myArray, 0, 1)
2. Return a copy of the Array (recommended)
func exchange<T>(data:[T], i:Int, j:Int) -> [T]
{
var newData = data
newData[i] = data[j]
newData[j] = data[i]
return newData
}
I recommend this way over the in-out parameter because in-out parameters create more complicated state. You have two variables pointing to and potentially manipulating the same piece of memory. What if exchange decided to do its work on a separate thread? There is also a reason that Apple decided to make arrays value types, using in-out subverts that. Finally, returning a copy is much closer to Functional Programming which is a promising direction that Swift can move. The less state we have in our apps, the fewer bugs we will create (in general).

Resources