Assume that I have an array like 1 2 3 4 5, I want to rotate it to the left by n and get a new one.
For example the 2 rotation of the above array will result in 3 4 5 1 2. I didn't found any extension function to do that.
You can use built-in java Collections.rotate method, but you need to convert your array to list firstly:
val arr = intArrayOf(1, 2, 3, 4, 5)
val list = arr.toList()
Collections.rotate(list, -2)
println(list.toIntArray().joinToString())
Outputs
3, 4, 5, 1, 2
I interpret "get a new one" to mean that the extension function should return a new array instance, like so (boundary checks omitted, sliceArray is an stdlib function) :
fun <T> Array<T>.rotate(n: Int) =
let { sliceArray(n until size) + sliceArray(0 until n) }
Example
arrayOf(1, 2, 3, 4, 5).rotate(1)
.also { println(it.joinToString()) } // 2, 3, 4, 5, 1
Another extension function, by slicing the array in 2 parts left and right and reassembling it to right + left:
fun <T> Array<T>.leftShift(d: Int) {
val n = d % this.size // just in case
if (n == 0) return // no need to shift
val left = this.copyOfRange(0, n)
val right = this.copyOfRange(n, this.size)
System.arraycopy(right, 0, this, 0, right.size)
System.arraycopy(left, 0, this, right.size, left.size)
}
so this:
val a = arrayOf(1, 2, 3, 4, 5, 6, 7)
a.leftShift(2)
a.forEach { print(" " + it) }
will print
3 4 5 6 7 1 2
Simple solution:
fun <T> Array<T>.rotateLeft(n: Int) = drop(n) + take(n)
fun <T> Array<T>.rotateRight(n: Int) = takeLast(n) + dropLast(n)
The limitation is that n must be less than or equal to the length of the array.
Alternatively, you can use Collections.rotate(...) as follows.
import java.util.Collections
fun <T> Array<T>.rotate(distance: Int) =
toList().also { // toList() is a deep copy to avoid changing the original array.
Collections.rotate(it, distance)
}
fun main() {
val xs = arrayOf(1, 2, 3, 4, 5)
val ys = xs.rotate(-2)
xs.forEach { print("$it ") } // 1 2 3 4 5
println(ys) // [3, 4, 5, 1, 2]
}
For the record, you can use the regular Array constructor to build a new array:
inline fun <reified T> Array<T>.rotate(n: Int) = Array(size) { this[(it + n) % size] }
The element at index it in the source array is copied in the destination array at the new index (it + n) % size to perform the rotation.
It is a bit slower than copying the array by chunks.
Related
I am trying to rotate an array from a particular position using array reversal method.
Input array: [1,2,3,4,5,6,7]
d = 3
Output array: [5,6,7,1,2,3,4]
To achieve this I thought of working on the array in three steps.
Step1: Reverse the array from starting position until d => [4,3,2,1,5,6,7]
Step2: Reverse the array from d till the end of the array => [4,3,2,1,7,6,5]
Step3: Reverse the complete array from Step2 => [5,6,7,1,2,3,4]
I haven't followed any functional programming pattern as I want to check the algorithm step by step.
val arr = Array[Int](1, 2, 3, 4, 5, 6, 7)
def reverseAlgo(brr: Array[Int], start: Int, end: Int): Unit = {
var temp = 0
for(i <- start until end/2) {
temp = brr(i)
brr(i) = brr(end-i-1)
brr(end-i-1) = temp
}
brr.foreach(println)
}
Step1 is working fine:
reverseAlgo(arr, 0, 3)
Output:
3
2
1
4
5
6
7
But Step2 is not producing the required output:
reverseAlgo(arr, 3, 7)
Output:
3
2
1
4
5
6
7
As you see, the output of the array should be: 3,2,1,7,6,5,4
Since the output from Step2 is incorrect, the final output is also wrong.
Step3:
reverseAlgo(arr, 0, arr.length)
Output:
7
6
5
4
1
2
3
Could anyone let me know what is the mistake I am doing here ?
Why not just something as simple as this?
import scala.collection.immutable.ArraySeq
import scala.reflect.ClassTag
def rotate[T : ClassTag](arr: ArraySeq[T])(pos: Int): ArraySeq[T] = {
val length = arr.length
ArraySeq.tabulate[T](n = length) { i =>
arr((i + 1 + pos) % length)
}
}
Which can be used like this:
rotate(arr = ArraySeq(1, 2, 3, 4, 5, 6, 7))(pos = 3)
// res: ArraySeq[Int] = ArraySeq(, 5, 6, 7, 1, 2, 3, 4)
You can see the code running here.
Your code will only work when the range starts at zero.
for(i <- start until end/2) {
temp = brr(i)
brr(i) = brr(end-i-1)
brr(end-i-1) = temp
}
Should be something like:
for(i <- 0 until (end-start)/2) {
temp = brr(start+i)
brr(start+i) = brr(end-i-1)
brr(end-i-1) = temp
}
With this change your code works.
Mutation is to be avoided but, if you must, recursion is still useful.
def reversePart[A](arr: Array[A], start: Int, end: Int): Unit = {
def loop(a:Int, b:Int): Unit =
if (a < b) {
val temp = arr(a)
arr(a) = arr(b)
arr(b) = temp
loop(a+1, b-1)
}
loop(start max 0, end min arr.length-1)
}
val test = Array(1, 2, 3, 4, 5, 6, 7)
reversePart(test, 0, 3) //Array(4, 3, 2, 1, 5, 6, 7)
reversePart(test, 4, 7) //Array(4, 3, 2, 1, 7, 6, 5)
reversePart(test, -1, 99) //Array(5, 6, 7, 1, 2, 3, 4)
I realize this doesn't directly answer your question, but for reference and for readers interested in a slightly different approach, one possibility is to implement this as a view.
In this example, Rotate implements the logic, while IndexedSeqViewRotate adds the rotate method as an extension to any IndexedSeqView as long as it's in scope.
In the tests, I materialized the views into Vectors to take advantage of the equality, but of course you can materialize them into an Array as well.
import scala.collection.IndexedSeqView
import scala.collection.IndexedSeqView.SomeIndexedSeqOps
final class Rotate[A](underlying: SomeIndexedSeqOps[A], n: Int) extends IndexedSeqView[A] {
#inline private def rotateIndex(i: Int): Int = ((i - n) % length + length) % length
override def apply(i: Int): A = underlying(rotateIndex(i))
override lazy val length: Int = underlying.length
}
final implicit class IndexedSeqViewRotate[A](val underlying: IndexedSeqView[A]) extends AnyVal {
def rotate(n: Int): IndexedSeqView[A] = new Rotate(underlying, n)
}
assert(Array().view.rotate(7).to(Vector) == Vector.empty)
assert(Array(1,2,3,4,5,6,7).view.rotate(7).to(Vector) == Vector(1,2,3,4,5,6,7))
assert(Array(1,2,3,4,5,6,7).view.rotate(0).to(Vector) == Vector(1,2,3,4,5,6,7))
assert(Array(1,2,3,4,5,6,7).view.rotate(1).to(Vector) == Vector(7,1,2,3,4,5,6))
assert(Array(1,2,3,4,5,6,7).view.rotate(3).to(Vector) == Vector(5,6,7,1,2,3,4))
assert(Array(1,2,3,4,5,6,7).view.rotate(-1).to(Vector) == Vector(2,3,4,5,6,7,1))
You can play around with this code here on Scastie.
I 'm trying to compare if two consecutive elements of an array are equal.
I have tried using for but as it returns a boolean but it does not seem to work what am I missing
val array1 = Array(1, 4, 2, 3)
def equalElements(array : Array[Int]) : Boolean = {
for (i <- 1 to (array.size )) {
if (array(i) == array(i + 1)) true else false
}
}
You can use sliding that
Groups elements in fixed size blocks by passing a "sliding window"
over them (as opposed to partitioning them, as is done in grouped.)
val array1 = Array(1, 1, 2, 2)
val equalElements = array1
.sliding(size = 2, step = 1) //step = 1 is a default value.
.exists(window => window.length == 2 && window(0) == window(1))
I am new to Scala and this is the first time I'm using it. I want to read in a textfile with with two columns of numbers and store each column items in a separate list or array that will have to be cast as integer. For example the textfile looks like this:
1 2
2 3
3 4
4 5
1 6
6 7
7 8
8 9
6 10
I want to separate the two columns so that each column is stored in its on list or array.
Lets say you named the file as "columns", this would be a solution:
val lines = Source.fromFile("columns").getLines()
/* gets an Iterator[String] which interfaces a collection of all the lines in the file*/
val linesAsArraysOfInts = lines.map(line => line.split(" ").map(_.toInt))
/* Here you transform (map) any line to arrays of Int, so you will get as a result an Interator[Array[Int]] */
val pair: (List[Int], List[Int]) = linesAsArraysOfInts.foldLeft((List[Int](), List[Int]()))((acc, cur) => (cur(0) :: acc._1, cur(1) :: acc._2))
/* The foldLeft method on iterators, allows you to propagate an operation from left to right on the Iterator starting from an initial value and changing this value over the propagation process. In this case you start with two empty Lists stored as Tuple an on each step you prepend the first element of the array to the first List, and the second element to the second List. At the end you will have to Lists with the columns in reverse order*/
val leftList: List[Int] = pair._1.reverse
val rightList: List[Int] = pair._2.reverse
//finally you apply reverse to the lists and it's done :)
Here is one possible way of doing this:
val file: String = ??? // path to .txt in String format
val source = Source.fromFile(file)
scala> val columnsTogether = source.getLines.map { line =>
val nums = line.split(" ") // creating an array of just the 'numbers'
(nums.head, nums.last) // assumes every line has TWO numbers only
}.toList
columnsTogether: List[(String, String)] = List((1,2), (2,3), (3,4), (4,5), (1,6), (6,7), (7,8), (8,9), (6,10))
scala> columnsTogether.map(_._1.toInt)
res0: List[Int] = List(1, 2, 3, 4, 1, 6, 7, 8, 6)
scala> columnsTogether.map(_._2.toInt)
res1: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)
Hi I've tried to insert element to rdd array[String] using scala in spark.
Here is example.
val data = RDD[Array[String]] = Array(Array(1,2,3), Array(1,2,3,4), Array(1,2)).
I want to make length 4 of all arrays in this data.
If the length of array is less than 4, I want to fill the NULL value in the array.
here is my code that I tried to solve.
val newData = data.map(x =>
if(x.length < 4){
for(i <- x.length until 4){
x.union("NULL")
}
}
else{
x
}
)
But The result is Array[Any] = Array((), Array(1, 2, 3, 4), ()).
So I tried another ways. I used yield on for loop.
val newData = data.map(x =>
if(x.length < 4){
for(i <- x.length until 4)yield{
x.union("NULL")
}
}
else{
x
}
)
The result is Array[Object] = Array(Vector(Array(1, 2, 3, N, U, L, L)), Array(1, 2, 3, 4), Vector(Array(1, 2, N, U, L, L), Array(1, 2, N, U, L, L)))
these are not what I want. I want to return like this
RDD[Array[String]] = Array(Array(1,2,3,NULL), Array(1,2,3,4), Array(1,2,NULL,NULL)).
What should I do?
Is there a method to solve it?
union is a functional operation, it doesn't change the array x. You don't need to do this with a loop, though, and any loop implementations will probably be slower -- it's much better to create one new collection with all the NULL values instead of mutating something every time you add a null. Here's a lambda function that should work for you:
def fillNull(x: Array[Int], desiredLength: Int): Array[String] = {
x.map(_.toString) ++ Array.fill(desiredLength - x.length)("NULL")
}
val newData = data.map(fillNull(_, 4))
I solved your use case with the following code:
val initialRDD = sparkContext.parallelize(Array(Array[AnyVal](1, 2, 3), Array[AnyVal](1, 2, 3, 4), Array[AnyVal](1, 2, 3)))
val transformedRDD = initialRDD.map(array =>
if (array.length < 4) {
val transformedArray = Array.fill[AnyVal](4)("NULL")
Array.copy(array, 0, transformedArray, 0, array.length)
transformedArray
} else {
array
}
)
val result = transformedRDD.collect()
I'm trying to add a tuple (e.g., 2-item tuple) to an array.
var myStringArray: (String,Int)[]? = nil
myStringArray += ("One", 1)
What I'm getting is:
Could not find an overload for '+=' that accepts the supplied
arguments
Hint: I tried to do an overload of the '+=' per reference book:
#assignment func += (inout left: (String,Int)[], right: (String,Int)[]) {
left = (left:String+right:String, left:Int+right+Int)
}
...but haven't got it right.
Any ideas? ...solution?
Since this is still the top answer on google for adding tuples to an array, its worth noting that things have changed slightly in the latest release. namely:
when declaring/instantiating arrays; the type is now nested within the braces:
var stuff:[(name: String, value: Int)] = []
the compound assignment operator, +=, is now used for concatenating arrays; if adding a single item, it needs to be nested in an array:
stuff += [(name: "test 1", value: 1)]
it also worth noting that when using append() on an array containing named tuples, you can provide each property of the tuple you're adding as an argument to append():
stuff.append((name: "test 2", value: 2))
You have two issues. First problem, you're not creating an "array of tuples", you're creating an "optional array of tuples". To fix that, change this line:
var myStringArray: (String,Int)[]? = nil
to:
var myStringArray: (String,Int)[]
Second, you're creating a variable, but not giving it a value. You have to create a new array and assign it to the variable. To fix that, add this line after the first one:
myStringArray = []
...or you can just change the first line to this:
var myStringArray: (String,Int)[] = []
After that, this line works fine and you don't have to worry about overloading operators or other craziness. You're done!
myStringArray += ("One", 1)
Here's the complete solution. A whopping two lines and one wasn't even changed:
var myStringArray: (String,Int)[] = []
myStringArray += ("One", 1)
Swift 4 solution:
// init empty tuple array
var myTupleArray: [(String, Int)] = []
// append a value
myTupleArray.append(("One", 1))
If you remove the optional, it works fine, otherwise you'll have to do this:
var myStringArray: (String,Int)[]? = nil
if !myStringArray {
myStringArray = []
}
var array = myStringArray!
array += ("One", 1)
myStringArray = array
You can never append an empty array, so you'll have to initialize it at some point. You'll see in the overload operator below that we sort of lazy load it to make sure that it is never nil.
You could condense this into a '+=' operator:
#assignment func += (inout left: Array<(String, Int)>?, right: (String, Int)) {
if !left {
left = []
}
var array = left!
array.append(right.0, right.1)
left = array
}
Then call:
var myStringArray: (String,Int)[]? = nil
myStringArray += ("one", 1)
I've ended up here multiple times due to this issue. Still not as easy as i'd like with appending onto an array of tuples. Here is an example of how I do it now.
Set an alias for the Tuple - key point
typealias RegionDetail = (regionName:String, constraintDetails:[String:String]?)
Empty array
var allRegionDetails = [RegionDetail]()
Easy to add now
var newRegion = RegionDetail(newRegionName, constraints)
allRegionDetails.append(newRegion)
var anotherNewRegion = RegionDetail("Empty Thing", nil)
allRegionDetails.append(anotherNewRegion)
Note:
It's not work anymore
if you do:
array += tuple
you will get error
what you need is :
array += [tuple]
I think apple change to this representation because it's more logical
#assignment func += (inout left: Array<(String, Int)>?, right: (String, Int)) {
if !left {
left = []
}
if left {
var array = left!
array.append(right.0, right.1)
left = array
}
}
var myStringArray: (String,Int)[]? = nil
myStringArray += ("x",1)
Thanks to comments:
import UIKit
#assignment func += (inout left: Array<(String, Int)>?, right: (String, Int)) {
if !left {
left = []
}
if left {
var array = left!
array.append(right.0, right.1)
left = array
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
println("interestingNumbers: \(interestingNumbers)\n")
var largest = 0
var myStringArray: (String,Int)[]? = nil
myStringArray += ("One", 1)
var x = 0
for (kind, numbers) in interestingNumbers {
println(kind)
for number in numbers {
if number > largest {
largest = number
}
x++
println("\(x)) Number: \(number)")
myStringArray += (kind,number)
} // end Number
} // end Kind
println("myStringArray: \(myStringArray)")
}
}
The Output:
interestingNumbers: [Square: [1, 4, 9, 16, 25], Prime: [2, 3, 5, 7,
11, 13], Fibonacci: [1, 1, 2, 3, 5, 8]]
Square 1) Number: 1 2) Number: 4 3) Number: 9 4)
Number: 16 5) Number: 25 Prime 6) Number: 2 7)
Number: 3 8) Number: 5 9) Number: 7 10) Number: 11
11) Number: 13 Fibonacci 12) Number: 1 13) Number:
1 14) Number: 2 15) Number: 3 16) Number: 5 17)
Number: 8
Array of tupules:
myStringArray: [(One, 1), (Square, 1), (Square, 4), (Square, 9),
(Square, 16), (Square, 25), (Prime, 2), (Prime, 3), (Prime, 5),
(Prime, 7), (Prime, 11), (Prime, 13), (Fibonacci, 1), (Fibonacci, 1),
(Fibonacci, 2), (Fibonacci, 3), (Fibonacci, 5), (Fibonacci, 8)]