Scala: How do I use foldLeft with a generic array? - arrays

I've this method:
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
val sorted = for (it <- as.sliding(2))
yield {
if (it.length == 2) ordered.apply(it(0), it(1))
else true
}
sorted.find(!_).isEmpty
}
What I'd like to do is use foldLeftand apply the binary operator. However, foldLeft requires an initial value and I don't know what initial value I can provide without knowing the real type of A.

I think what you're doing can be simplified.
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
if (as.size < 2)
true
else
as.sliding(2).find(x => !ordered(x(0),x(1))).isEmpty
}
isSorted: [A](as: Array[A], ordered: (A, A) => Boolean)Boolean
scala> isSorted( Array(2), {(a:Int,b:Int) => a < b} )
res42: Boolean = true
scala> isSorted( Array(2,4), {(a:Int,b:Int) => a < b} )
res43: Boolean = true
scala> isSorted( Array(2,4,5), {(a:Int,b:Int) => a < b} )
res44: Boolean = true
scala> isSorted( Array(2,14,5), {(a:Int,b:Int) => a < b} )
res45: Boolean = false
Or, perhaps a little more concisely (but not necessarily easier to understand):
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
if (as.size < 2)
true
else
!as.sliding(2).exists(x => ordered(x(1),x(0)))
}
UPDATE
OK, I think I've got the concise prize nailed.
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean =
as.isEmpty || as.init.corresponds(as.tail)(ordered)

For initial value for foldLeft you could use head of your input array. However foldLeft is not a good choise to check if array is sorted, since you should terminate method when first unsorted element found but foldLeft will traverse whole array
Edit:
I would use the combination of zip with tail and exists:
isSorted(...) =
if (as.isEmpty) true
else !as.zip(as.tail).exists { case (a,b) => !ordered(a,b)}

Adding to the other answers, you probably do not want to iterate through the entire array, but rather terminate the moment you find an unordered pair. So, how about this?
def isSorted[A](as: Array[A], ordered: (A, A) => Boolean): Boolean = {
var sorted = true
val ita = as.sliding(2)
while (sorted && ita.hasNext) {
val it = ita.next
sorted = if (it.size > 1) ordered(it(0), it(1)) else true
}
sorted
}
val a = Array(1, 3, 2, 4, 5)
val b = Array(1, 2, 3, 4, 5)
isSorted[Int](a, _ < _) // returns false
isSorted[Int](b, _ < _) // returns true

Related

Iterating through references to variables in Swift

I am looking for a way to change the values of multiple variables using iteration in Swift. An example would be something like this:
var a = false
var b = false
var c = false
func makeAllTrue() {
for n in [a, b, c] {
n = true
}
}
...but rather than an array of values, I want to iterate through an array of pointers/references to the variables above.
Any advice would be greatly appreciated.
var a = false
var b = false
var c = false
mutateValues(&a, &b, &c) { n in
n = true
}
print(a, b, c) // will be printed "true true true"
func mutateValues<Value>(_ values: UnsafeMutablePointer<Value>..., mutate: (inout Value) -> Void) {
values.forEach {
mutate(&$0.pointee)
}
}
It is possible to do this with key paths. Let's say the properties are in a class Foo:
class Foo {
var a = false
var b = false
var c = false
func makeAllTrue() {
for n in [\Foo.a, \Foo.b, \Foo.c] {
self[keyPath: n] = true
}
}
}
If Foo is a struct, use mutating func instead:
struct Foo {
var a = false
var b = false
var c = false
mutating func makeAllTrue() {
for n in [\Foo.a, \Foo.b, \Foo.c] {
self[keyPath: n] = true
}
}
}
However, if the class name is long, I don't think it is worth doing this way.
If these three properties are very related, I would not bother with the key path stuff and replace a, b and c with an array:
var abc = [false, false, false]
and have the for loop loop over the indices:
for i in abc.indices {
abc[i] = true
}
An Array in Swift is a struct, hence a value type.
Iterating over his children, and changing one, will not be possible unless:
The type of child is aa class (which is reference typed)
You iterate over the indices and change the real values!
E.G:
var a: Int = 1
var b: Int = 2
var array: [Int] = [a,b]
for index in array.indices {
array[index] += 1
}
print(array) // [2,3]

Get indexes from one array and update elements on same indexes in second array

I have two arrays, upper and lower bound.
val solution : Array[Double] = Array(1.0, 33.0, 31.0, 82.0, 51.0, 25.0, 39.0, 96.0, 95.0, 49.0)
val original : Array[Double] = Array(3.0, 45.0, 18.0, 25.0, 99.0, 6.0, 36.0, 61.0, 82.0, 62.0)
val lower = 30
val upper = 90
Array of type Boolean is created using solution array.
val idx_lowest : Array[Boolean] = solution.map ( x => x < lower )
idx_lowest: Array[Boolean] = Array(true, false, false, false, false, true, false, false, false, false)
Find indexes in idx_lowest where value is true
val trueIndexes = idx_lowest .zipWithIndex filter(x => x._1 ) map(_._2)
trueIndexes: Array[Int] = Array(0, 5)
Find values against trueIndexes in original array.
val tmp = trueIndexes map original
Array[Double] = Array(3.0, 6.0)
Perform operation on elements of tmp array.
val tmp1 = tmp map (x => (x+lower)/2.0)
Array[Double] = Array(16.5, 18.0)
Update elements of solution array. Indexes are specified by trueIndexes. Elements those are less than lower bound are updated.
for(i <- tmp1.indices) {
solution(trueIndexes(i)) = tmp1(i)
}
The updated solution array is:
Array[Double] = Array(16.5, 33.0, 31.0, 82.0, 51.0, 18.0, 39.0, 96.0, 95.0, 49.0)
Same steps have to be performed to update elements that are greater than upper bound. Here is code.
val idx_false : Array[Boolean] = solution.map ( x => x > upper )
val falseIndexes = idx_false .zipWithIndex filter(x => x._1 ) map(_._2)
val tmp2 = falseIndexes map original
val tmp3 = tmp2 map (x => (x+upper)/2.0)
for(i <- tmp3.indices) {
solution(falseIndexes(i)) = tmp3(i)
}
solution
This code doing exactly what I needed but have to perform lot of operations. In iterative algorithm I have to perform these operation in each iteration for each array. Is there more efficient,optimal and faster way to perform same operation?
You can zip them and map in a single operation:
solution.zip(original)
.map { case(s, o) => if(s < lower) ((o + lower) / 2, o) else (s, o) }
.map { case(s, o) => if(s > upper) (o + upper) / 2 else s }
Isn't this the same result?
val done = solution.indices.map{x =>
if (solution(x) < lower) (lower + original(x))/2.0
else if (solution(x) > upper) (upper + original(x))/2.0
else solution(x)
}.toArray

How to reduce positive elements in collection in scala?

Given an integer array nums:
-2,1,-3,4,6,-1,2,1,1,-5,4
I want to transform this array to another array:
-2,1,-3,10,-1,4,-5,4
Can I add a condition to the reduce function?
Something like that:
...
val nums = Array(-2,1,-3,4,6,-1,2,1,1,-5,4)
val reduced = nums.reduce((x, y) => {
if (x > 0 && y > 0){
x + y
}
})
...
scala> val nums = Array(-2,1,-3,4,6,-1,2,1,1,-5,4)
nums: Array[Int] = Array(-2, 1, -3, 4, 6, -1, 2, 1, 1, -5, 4)
scala> nums.foldLeft(List[Int]()){
case (init :+ last, num) if last > 0 && num > 0 => init :+ (last + num)
case (res, num) => res :+ num
}
res0: List[Int] = List(-2, 1, -3, 10, -1, 4, -5, 4)
Or:
scala> def reduce(nums: Seq[Int]): Seq[Int] = nums match {
| case x1+:x2+:xs => if(x1>0 && x2>0) reduce((x1+x2)+:xs) else x1+:reduce(x2+:xs)
| case ns => ns
| }
def reduce(nums: Seq[Int]): Seq[Int]
scala> reduce(nums)
val res1: Seq[Int] = ArraySeq(-2, 1, -3, 10, -1, 4, -5, 4)
You can try next:
val result = Array(-2,1,-3,4,6,-1,2,1,1,-5,4).foldLeft(ListBuffer.empty[Int]) {
case (result, item) if item < 0 => result :+ item
case (result, item) if item > 0 => result.lastOption.filter(_ > 0).fold(result :+ item) { positiveSum =>
result.update(result.size -1, positiveSum + item)
result
}
}
println(result)
which will produce desired result: (-2, 1, -3, 10, -1, 4, -5, 4)
Hope this helps!
I am not sure if you can use reduce or another simple builtin-function to achieve your goal.
However, you can write a simple tail-recursive function that does what you want (it uses a list and pattern matching):
def sumPositives(arr: Array[Integer]): Array[Integer] = {
#scala.annotation.tailrec
def rec(list: List[Integer], acc: List[Integer]): List[Integer] = list match{
case x :: y :: rest if x >= 0 && y >= 0 => rec(x+y :: rest, acc)
case x :: y :: rest => rec(y :: rest, x :: acc)
case x :: Nil => (x :: acc).reverse
case Nil =>acc.reverse
}
rec(arr.toList, List()).toArray
}
Of course this could be simplified by using a list as input instead of an array, but in your question you specifically mentioned an array.
A simple, non-tail recursive one:
def reducePositives(l: List[Int]): List[Int] = {
l.span(_ > 0) match {
case (Nil, Nil) => Nil
case (Nil, np :: rest) => np :: reducePositives(rest)
case (p, rest) => p.sum :: reducePositives(rest)
}
}

Conditionally extract hashes from array of hashes

From the following array of hashes:
x = [
{"creationDate"=>123456,"createdBy"=>"test_user1"},
{"creationDate"=>123459,"createdBy"=>"test_user1"},
{"creationDate"=>123458,"createdBy"=>"test_user1"},
{"creationDate"=>123454,"createdBy"=>"test_user2"},
{"creationDate"=>123452,"createdBy"=>"test_user2"},
{"creationDate"=>123451,"createdBy"=>"test_user2"}
]
I am trying to find the maximum :creationDate value where :createdBy value is "test_user1". I did this:
x.map {|a| a['creationDate'] if a['createdBy'] == 'test_user1'}
# => [123456,123459,123458,nil,nil,nil]
I want to get rid of the nil so that I can apply max to that array. How do I modify the code above?
What you want to do here is:
x.select { |record| record[:createdBy] == 'test_user1' }.map { |record| record[:creationDate] }.max
# => 123459
In general, to remove nils from an array, you can simply call Array#compact:
[1, nil, nil, 2, 'foo', nil].compact # => [1, 2, "foo"]
It' close to what you plan to do in python:
x.select { |n| n[:createdBy] == "test_user1" }.max_by { |n| n[:creationDate] }
First operation select on records created by "test_user1", while second operation get the maximum of the resulting array based on the creationDate
I'd guess something like :
x.delete_if {|x| x == nil}
This is a good candidate for a map-reduce function such as inject.
x = [{"creationDate" => 123456,"createdBy" => "test_user1"},
{"creationDate" => 123459,"createdBy" => "test_user1"},
{"creationDate" => 123458,"createdBy" => "test_user1"},
{"creationDate" => 123454,"createdBy" => "test_user2"},
{"creationDate" => 123452,"createdBy" => "test_user2"},
{"creationDate" => 123451,"createdBy" => "test_user2"}]
x.inject(nil) do |result, item|
if item["createdBy"] == "test_user1" && (result.nil? or item["creationDate"] > result)
item["creationDate"]
else
result
end
end
Here's a possible implementation of the inject. The block will iterate each item in the collection and will always maintain the highest value.
x.min_by{|h| [h[:createdBy], -h[:creationDate]]}[:creationDate]
# => 123459
[123456, 123459, 123458, nil, nil, nil].compact
# => [123456, 123459, 123458]
This works:
x.map {|a| a['creationDate'] if a['createdBy'] == 'test_user1'}.compact.max
# => 123459

check if all elements of an array have the same value in Swift

Is there a function in Swift that checks whether all elements of an array have the same value? In my case, it's an array of type Int. I know I can iterate over it using a simple for loop I was just wondering if there is something that is built in and quicker.
With Swift 5, you can use one of the four following ways in order to tests if all elements of an array are equal.
#1. Using Array's allSatisfy(_:) method
allSatisfy(_:) returns a Boolean value indicating whether every element of a sequence satisfies a given predicate. You can set the predicate to test if all elements of the array are equal:
let array = [1, 1, 1]
let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: false
let array = [Int]()
let hasAllItemsEqual = array.dropFirst().allSatisfy({ $0 == array.first })
print(hasAllItemsEqual) // prints: true
#2. Using Array's reduce(_:_:) method
As an alternative to allSatisfy(_:), you can use reduce(_:_:):
let array = [1, 1, 1]
let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: false
let array = [Int]()
let hasAllItemsEqual = array.dropFirst().reduce(true) { (partialResult, element) in
return partialResult && element == array.first
}
print(hasAllItemsEqual) // prints: true
#3. Using elementsEqual(_:) method
elementsEqual(_:) returns a Boolean value indicating whether two sequences contain the same elements in the same order. Therefore you can create a new collection by repeating the first element of the initial array and compare the former with the latter:
let array = [1, 1, 1]
precondition(!array.isEmpty)
let repeated = repeatElement(array[0], count: array.count)
let hasAllItemsEqual = array.elementsEqual(repeated)
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
precondition(!array.isEmpty)
let repeated = repeatElement(array[0], count: array.count)
let hasAllItemsEqual = array.elementsEqual(repeated)
print(hasAllItemsEqual) // prints: false
#4. Using Set's init(_:) initalizer
If all elements of an array are equal, creating a set from this array should result in the set having only one element:
let array = [1, 1, 1]
let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: true
let array = [1, 1, 3]
let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: false
let array = [Int]()
let set = Set(array)
let hasAllItemsEqual = set.count <= 1
print(hasAllItemsEqual) // prints: true
Any method must iterate over all elements until a different element is found:
func allEqualUsingLoop<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
for elem in array {
if elem != firstElem {
return false
}
}
}
return true
}
Instead of an explicit loop you can use the contains() function:
func allEqualUsingContains<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
return !contains(array, { $0 != firstElem })
}
return true
}
If the array elements are Hashable (such as Int) then you can
create a Set (available since Swift 1.2) from the array elements and check if it has exactly one element.
func allEqualUsingSet<T : Hashable>(array : [T]) -> Bool {
let uniqueElements = Set(array)
return count(uniqueElements) <= 1
}
A quick benchmarking test revealed that the "contains" method is much faster than the "set" method
for an array of 1,000,000 integers, in particular if the elements are
not all equal. This make sense because contains() returns as soon
as a non-matching element is found, whereas Set(array) always
traverses the entire array.
Also the "contains" methods is equally fast or slightly faster than an explicit loop.
Here is some simple benchmarking code. Of course the results can vary
with the array size, the number of different elements and the elements data type.
func measureExecutionTime<T>(title: String, #noescape f : (() -> T) ) -> T {
let start = NSDate()
let result = f()
let end = NSDate()
let duration = end.timeIntervalSinceDate(start)
println("\(title) \(duration)")
return result
}
var array = [Int](count: 1_000_000, repeatedValue: 1)
array[500_000] = 2
let b1 = measureExecutionTime("using loop ") {
return allEqualUsingLoop(array)
}
let b2 = measureExecutionTime("using contains") {
allEqualUsingContains(array)
}
let b3 = measureExecutionTime("using set ") {
allEqualUsingSet(array)
}
Results (on a MacBook Pro, Release configuration):
using loop 0.000651001930236816
using contains 0.000567018985748291
using set 0.0344770550727844
With array[1_000] = 2 the results are
using loop 9.00030136108398e-06
using contains 2.02655792236328e-06
using set 0.0306439995765686
Update for Swift 2/Xcode 7: Due to various changes in the Swift
syntax, the function is now written as
func allEqual<T : Equatable>(array : [T]) -> Bool {
if let firstElem = array.first {
return !array.dropFirst().contains { $0 != firstElem }
}
return true
}
But you can now also define it as an extension method for arrays:
extension Array where Element : Equatable {
func allEqual() -> Bool {
if let firstElem = first {
return !dropFirst().contains { $0 != firstElem }
}
return true
}
}
print([1, 1, 1].allEqual()) // true
print([1, 2, 1].allEqual()) // false
Soliution for Swift 4.2/Xcode 10:
let arr = [1, 1, 1, 1]
let allItemsEqual = arr.dropLast().allSatisfy { $0 == arr.last }
print(allItemsEqual)
If your current version of Xcode is prior to 10.0 you can find the function allSatisfy of ArraySlice in Xcode9to10Preparation. You can install this library with CocoaPods.
let ints: [Int] = [1, 1, 1, 1]
print(ints.max() == ints.min())
If you have float buffers or if you already have an array of floats (or you think converting to floats beforehand is convenient):
import Accelerate
// [...]
// let floats = ints.map({ Double($0) })
print(vDSP.minimum(floats) == vDSP.maximum(floats))

Resources