How can I get hold of a column or row of a 2D Array in F# (ideally as a 1D array, but a Seq would be nice as well). Obviously I could write it myself, but you would think it must be already provided...
E.g. I am after built-in equivalent for:
let row i array = seq { for j in 0 .. (Array2D.length2 array)-1 do yield array.[i,j]}
I don't think there is a built-in function for this.
You could slice the array and flatten the slice using Seq.cast:
let row i (arr: 'T[,]) = arr.[i..i, *] |> Seq.cast<'T>
Related
I have an array that is storing a large number of various names in string format. There can be duplicates.
let myArray = ["Jim","Tristan","Robert","Lexi","Michael","Robert","Jim"]
In this case I do NOT know what values will be in the array after grabbing the data from a parse server. So the data imported will be different every time. Just a list of random names.
Assuming I don't know all the strings in the array I need to find the index of the last occurrence of each string in the array.
Example:
If this is my array....
let myArray = ["john","john","blake","robert","john","blake"]
I want the last index of each occurrence so...
blake = 5
john = 4
robert = 3
What is the best way to do this in Swift?
Normally I would just make a variable for each item possibility in the array and then increment through the array and count the items but in this case there are thousands of items in the array and they are of unknown values.
Create an array with elements and their indices:
zip(myArray, myArray.indices)
then reduce into a dictionary where keys are array elements and values are indices:
let result = zip(myArray, myArray.indices).reduce(into: [:]) { dict, tuple in
dict[tuple.0] = tuple.1
}
(myArray.enumerated() returns offsets, not indices, but it would have worked here too instead of zip since Array has an Int zero-based indices)
EDIT: Dictionary(_:uniquingKeysWith:) approach (#Jessy's answer) is a cleaner way to do it
New Dev's answer is the way to go. Except, the standard library already has a solution that does that, so use that instead.
Dictionary(
["john", "john", "blake", "robert", "john", "blake"]
.enumerated()
.map { ($0.element, $0.offset) }
) { $1 }
Or if you've already got a collection elsewhere…
Dictionary(zip(collection, collection.indices)) { $1 }
Just for fun, the one-liner, and likely the shortest, solution (brevity over clarity, or was it the other way around? :P)
myArray.enumerated().reduce(into: [:]) { $0[$1.0] = $1.1 }
I am new to Swift and am struggling to work out how to determine the size of a multidimensional array.
I can use the count function for single arrays, however when i create a matrix/multidimensional array, the output for the count call just gives a single value.
var a = [[1,2,3],[3,4,5]]
var c: Int
c = a.count
print(c)
2
The above matrix 'a' clearly has 2 rows and 3 columns, is there any way to output this correct size.
In Matlab this is a simple task with the following line of code,
a = [1,2,3;3,4,5]
size(a)
ans =
2 3
Is there a simple equivalent in Swift
I have looked high and low for a solution and cant seem to find exactly what i am after.
Thanks
- HB
Because 2D arrays in swift can have subarrays with different lengths. There is no "matrix" type.
let arr = [
[1,2,3,4,5],
[1,2,3],
[2,3,4,5],
]
So the concept of "rows" and "columns" does not exist. There's only count.
If you want to count all the elements in the subarrays, (in the above case, 12), you can flat map it and then count:
arr.flatMap { $0 }.count
If you are sure that your array is a matrix, you can do this:
let rows = arr.count
let columns = arr[0].count // 0 is an arbitrary value
You must ask the size of a specific row of your array to get column sizes :
print("\(a.count) \(a[0].count)")
If you are trying to find the length of 2D array which in this case the number of rows (or # of subarrays Ex.[1,2,3]) you may use this trick: # of total elements that can be found using:
a.flatMap { $0 }.count //a is the array name
over # of elements in one row using:
a[0].count //so elemints has to be equal in each subarray
so your code to get the length of 2D array with equal number of element in each subarray and store it in constant arrayLength is:
let arrayLength = (((a.flatMap { $0 }.count ) / (a[0].count))) //a is the array name
if I have a two-dimensional array like this: [[1,2,3], [3,2,1], [4,9,3]], I want to be able to find out that there are two identical arrays inside this array, which are [1,2,3] and [3,2,1]. How can I achieve this?
Thank you for all your answers, I was focusing on the leetCode threeSum problem so I didn't leave any comment. But since I am a programming noobie, my answer exceeded the time limit.. so I actually wanted to find the duplicated arrays and remove all the duplicates and leave only one unique array in the multi-dimensional array. I have added some extra code based on #Oleg's answer, and thought I would put my function here :
func removeDuplicates(_ nums: inout [[Int]] ) -> [[Int]]{
let sorted = nums.map{$0.sorted()}
var indexs = [Int]()
for (pos,item) in sorted.enumerated() {
for i in pos+1..<sorted.count {
if item == sorted[i] {
if nums.indices.contains(i){
indexs.append(i)
}
}
}
}
indexs = Array(Set<Int>(indexs))
indexs = indexs.sorted(by: {$0 > $1})
for index in indexs{
nums.remove(at: index)
}
return nums
}
My solution is quite simple and easy to understand.
let input = [[1,2,3], [3,2,1], [4,9,3]]
First let sort all elements of the nested arrays. (It gives us a bit more efficiency.)
let sorted = input.map{$0.sorted()}
Than we should compare each elements.
for (pos,item) in sorted.enumerated() {
for i in pos+1..<sorted.count {
if item == sorted[i] {
print(input[pos])
print(input[i])
}
}
}
Output:
[1, 2, 3]
[3, 2, 1]
One simple and easy brute force approach that comes to my mind is:
Iterate over each row and sort its values. So 1,2,3 will become 123 and 3,2,1 will also become 1,2,3.
Now store it in a key value pair i.e maps. So your key will be 123 and it will map to array 1,2,3 or 3,2,1.
Note:- Your key is all the sorted elements combined together as string without commas.
This way you will know that how may pairs of arrays are there inside a 2d array are identical.
There is a very efficient algorithm using permutation hashing method.
1) preprocess the 2-dim array so that all elements are non-negative. (by subtracting the smallest element from all elements)
2) with each sub-array A:
compute hash[A] = sum(base^A[i] | with all indexes i of sub-array A). Choose base to be a very large prime (1e9+7 for example). You can just ignore the integer-overflow problem when computing, because we use only additions and multiplications here.
3) now you have array "hash" of each sub-array. If the array has 2 identical sub-arrays, then they must have the same hash codes. Find all pairs of sub-arrays having equal hash codes(using hash again, or sorting, ... whatever).
4) For each pair, check again if these sub-arrays actually match (sort and compare, ... whatever). Return true if you can find 2 sub-arrays that actually match, false otherwise.
Practically, this method runs extremely fast even though it is very slow theoretically. This is because of the hashing step will prune most of search space, and this hash function is super strong. I am sure 99.99% that if exist, the pair of corresponding sub-arrays having the same hash codes will actually match.
I am trying to sort an Array by using fold or foldBack.
I have tried achieving this like this:
let arraySort anArray =
Array.fold (fun acc elem -> if acc >= elem then acc.append elem else elem.append acc) [||] anArray
this ofcourse errors horribly. If this was a list then i would know how to achieve this through a recursive function but it is not.
So if anyone could enlighten me on how a workable function given to the fold or foldback could look like then i would be createful.
Before you start advising using Array.sort anArray then this wont do since this is a School assignment and therefore not allowed.
To answer the question
We can use Array.fold for a simple insertion sort-like algorithm:
let sort array =
let insert array x =
let lesser, greater = Array.partition (fun y -> y < x) array
[| yield! lesser; yield x; yield! greater |]
Array.fold insert [||] array
I think this was closest to what you were attempting.
A little exposition
Your comment that you have to return a sorted version of the same array are a little confusing here - F# is immutable by default, so Array.fold used in this manner will actually create a new array, leaving the original untouched. This is much the same as if you'd converted it to a list, sorted it, then converted back. In F# the array type is immutable, but the elements of an array are all mutable. That means you can do a true in-place sort (for example by the library function Array.sortInPlace), but we don't often do that in F#, in favour of the default Array.sort, which returns a new array.
You have a couple of problems with your attempt, which is why you're getting a few errors.
First, the operation to append an array is very different to what you attempted. We could use the yield syntax to append to an array by [| yield! array ; yield element |], where we use yield! if it is an array (or in fact, any IEnumerable), and yield if it is a single element.
Second, you can't compare an array type to an element of the array. That's a type error, because compare needs two arguments of the same type, and you're trying to give it a 'T and a 'T array. They can't be the same type, or it'd be infinite ('T = 'T array so 'T array = 'T array array and so on). You need to work out what you should be comparing instead.
Third, even if you could compare the array to an element, you have a logic problem. Your element either goes right at the end, or right at the beginning. What if it is greater than the first element, but less than the last element?
As a final point, you can still use recursion and pattern matching on arrays, it's just not quite as neat as it is on lists because you can't do the classic | head :: tail -> trick. Here's a basic (not-so-)quicksort implementation in that vein.
let rec qsort = function
| [||] -> [||]
| arr ->
let pivot = Array.head arr
let less, more = Array.partition (fun x -> x < pivot) (Array.tail arr)
[| yield! qsort less ; yield pivot ; yield! qsort more |]
The speed here is probably several orders of magnitude slower than Array.sort because we have to create many many arrays while doing it in this manner, which .NET's Array.Sort() method does not.
I have an an array of tuples defined like this:
var stringsWithLengthsArray:[(someString: String, someStringLength: Int)] = []
I've appended a number of tuples to this array. I would like to sum the someStringLength elements of each tuple in the array and think the best way to do this is to use the stringsWithLengthsArray.reduce method, but I can't figure out the syntax. What's the best way to sum the someStringLength elements?
I like this way best:
let total = stringsWithLengthsArray.reduce(0){$0 + $1.someStringLength}
This is another solution. Use reduce without map and access your tuple fields with the .0 / .1 accessors directly.
let total = stringsWithLengthsArray.reduce(0){$0 + $1.1}
You can use map to get only the someStringLength property value and use reduce to sum all the elements as follow:
let stringsWithLengthsArray:[(someString: String, someStringLength: Int)] = [("strA",2),("strB",3)]
let someStringLenghtTotal = stringsWithLengthsArray.map{$0.someStringLength}.reduce(0){$0+$1}
someStringLenghtTotal // 5