scala searching nested arrays - arrays

I'm trying to search a nested array of characters for a specific character, and then return the indices of the character from the array.
Code Snippet
def search(target: Char, arr:Array[Array[Char]]): List[Int] = {
for (i <- 0 until arr.length) { //search through first layer of array
for (j <- 0 until arr(i).length) { //search through second layer of array
if (arr(i)(j) == target) {
val x = List(i,j)
return x
} }}}
However, I'm getting an error from compilation, that says this function is returning the two type signature. Error message:
error: type mismatch;
found : Unit
required: List[Int]
for (i <- 0 until arr.length) { //search through first layer of array
^
I've found two similar threads here: found Unit: required Int. Why is the error not obvious?
and found: Unit required: Int - How to correct this?
but they don't solve the problem i'm facing: I am trying to return the List, but the compiler is getting stuck at the for loop..

Seems like there are a lot of answers already, but I think that this is the most idiomatic way to approach the problem:
The Code
def search(target: Char, arr: Array[Array[Char]]): List[(Int, Int)] = {
val indices = for{
(a, i) <- arr.iterator.zipWithIndex
(c, j) <- a.iterator.zipWithIndex
if( c == target )
} yield i -> j
indices.toList
}
The Explanation
In scala, for-comprehensions are nestable, so you can take care of any degree of nested arrays by simply adding another x <- y line. You can introduce filtering with an if statement inside of the for{...}.
In the comprehension, a is the ith array inside arr, where i is the first index. c is the jth character inside a, where j is the second index. I use iterator so that indices can be evaluated on the fly, without needing to copy the arrays behind the scenes because of the for-comprehension. At the end, I call toList to evaluate the results of the indices iterator into a list.
The return type, List[(Int, Int)] is a list of pairs. It makes more sense to return List( (1,2), (3,4) ) if you found your target at i=1, j=2 and i=3, j=4 than to return List(1,2,3,4).
General Thoughts
Try to avoid using return in scala. You can usually handle your collections with an iterator-like approach, using yield, and then evaluate the result by calling a toList or toMap or toWhatever.
The scala collections API is very helpful for many of these cases, too. In the case where you just want the first item that matches a condition, you can use myCollection.find(...). Explore the scala docs to see the huge variety of convenient functions that are already available to you.

I would suggest using a less Java-like approach altogether. I'm not entirely sure what your function is supposed to do, but if you want a list of all (x, y) indices of the match within the nested array, you could do something like this:
def search(target: Char, array: Array[Array[Char]]): Seq[(Int, Int)] = {
array.zipWithIndex.filter(_._1.contains(target)).map { xa =>
xa._1.zipWithIndex.filter(_._1 == target).map(xb => (xa._2, xb._2)).toSeq
}.flatten.toSeq
}
which behaves like this:
val t = Array(
Array('a', 'b', 'c'),
Array('b'), Array('c', 'a'),
Array('a', 'a', 'x', 'a')
)
println(search('a', t))
=> ((0,0), (2,1), (3,0), (3,1), (3,3))

Here is my solution to find the first index of a element in a two-dimension array:
(replace collectFirt to collect, if you wan to find all indexes)
def search[T](target: T, arr: Array[Array[T]]): List[Int] =
arr.indices.collectFirst{
case k if arr(k).contains(target) =>
List(k, arr(k).indexWhere(_ == target))
}.getOrElse(Nil)
Test:
scala> val t = Array(
| Array('a', 'b', 'c'),
| Array('b'),
| Array('c', 'a'),
| Array('a', 'a', 'x', 'a')
| )
scala> println(search('a', t))
List(0, 0)
scala> println(search('x', t))
List(3, 2)
scala> println(search('e', t))
List()

You only return a List if a particular condition is met (arr(i)(j) == target). You have to define a return value for the case that the for comprehensions run through. E.g.
def search(target: Char, arr:Array[Array[Char]]): List[Int] = {
for (i <- 0 until arr.length) { //search through first layer of array
for (j <- 0 until arr(i).length) { //search through second layer of array
if (arr(i)(j) == target) {
val x = List(i,j)
return x
}
}
}
Nil // not found
}

The for loop itself would return Unit if the second array is empty or the if expression evaluates to false. You could rewrite it so it returns null if it nevers gets to the code after the if-expression.
I would leave out the assignment of x too, there's really no point.
def search(target: Char, arr:Array[Array[Char]]): List[Int] =
{
for (i <- 0 until arr.length)
{ //search through first layer of array
for (j <- 0 until arr(i).length)
{ //search through second layer of array
if (arr(i)(j) == target)
{
return List(i,j)
}
}
}
Nil
}
Btw this could probably be rewritten with a more functional approach but that goes beyond the scope of this question.

Related

How to remove every element in an array after a conditional?

So I have an array of strings in Scala called pronunciationArray like this:
["EH1","N", "D", "P", "ER0", "EH1", "N", "TH", "AH0", "S", "IY2", "Z"]
and i want to write an if else statement that reads the array in reverse, and as soon as it finds a string with a number in it, it either removes all the strings after or puts everything before into a separate array.
so for the above example, id want it to stop at "IY2", then either create a new array with only ["IY2", "Z"] or remove every string after and leave the original array with, like I said, ["IY2", "Z"]. The number itself isnt an integer btw, its part of the string, and the numbers range from 0-2.
I've tried for loop in reverse with an if else that looks for the numbers 0, 1, 2 but it returns every string with a number, so it returns [IY2, AH0, EH1, ER0, EH1] it doesnt stop as soon as it finds the first string with a number. And i'm not sure how to put everything before that string into a new array if I even found a way to stop it.
for (sounds <- pronunciationArray.reverse) {
val number0 = sounds.contains("0")
if (number0 == true) {
println(sounds)
} else if (number0 == true){
println(sounds)
} else if (number1 == true){
println(sounds)
} else {
-1
}
}
I want it to return just ["IY2", "Z"] but it returned [IY2, AH0, EH1, ER0, EH1]
One of the algorithm you can solve with is
find the index of element from the last where element has 0, 1 or 2
split the array at above index
take the last element of first array and whole second array
Example,
val pronunciationArray = Array("EH1","N", "D", "P", "ER0", "EH1", "N", "TH", "AH0", "S", "IY2", "Z")
def takeUntil(inputArray: Array[String], condition: String => Boolean): Array[String] = {
val findIndexFromLast = inputArray.reverse.zipWithIndex.collectFirst {
case (elem, index) if condition.apply(elem) => index
}
findIndexFromLast match { // pattern match to check if there exists element with 0, 1, or 2
case Some(indexFromLast) =>
inputArray.splitAt(inputArray.length - indexFromLast) match {
case (head, tail) => head.last +: tail
}
case None => // no element with 0, 1, 2 exists
inputArray
}
}
takeUntil(
inputArray = pronunciationArray,
condition = elem => elem.contains("0") || elem.contains("1") || elem.contains("2")) //gives [IY2, Z]
The other way to solve the same using .span(predicate) which is better version of .splitAt(index)
def takeUntil2(inputArray: Array[String]): Array[String] = {
inputArray.reverse.span {
element =>
!element.contains("0") && !element.contains("1") && !element.contains("2")
} match {
case (head, tail) => tail.take(1) ++ head.reverse
}
}
val result = takeUntil2(inputArray = pronunciationArray)
Now, using scala way you can extend Array to have custom function,
implicit class ArrayOps(array: Array[String]) {
def takeUntil(predicate: String => Boolean): Array[String] = {
val splitAt = array.reverse.span(predicate.apply)
splitAt._2.take(1) ++ splitAt._1.reverse
}
}
val res = pronunciationArray
.takeUntil(predicate = elem => !elem.contains("0") && !elem.contains("1") && !elem.contains("2"))
Similar question:
How to implement 'takeUntil' of a list?
How do I pattern match arrays in Scala?
I'm not completely clear on your objective, but Array has a span function that splits it into two pieces based on a condition--the first piece is a prefix of the array where everything satisfies the condition and the second piece is the remainder.
Let's say your condition was that the string contains 2 rather than contains a number (just because I'm lazy--it could be any function f: String => Boolean). If we reverse the array and then split on the negation of the function, we get:
scala> a.reverse.span(!_.contains("2"))
res5: (Array[String], Array[String]) = (Array(Z),Array(IY2, S, AH0, TH, N, EH1, ER0, P, D, N, EH1))
We know that the first element of the second array satisfies our condition, so we can just assemble the result:
scala> val (start, end) = a.reverse.span(!_.contains("2"))
start: Array[String] = Array(Z)
end: Array[String] = Array(IY2, S, AH0, TH, N, EH1, ER0, P, D, N, EH1)
scala> val result = end.take(1) ++ start.reverse
result: Array[String] = Array(IY2, Z)
All the reversing is perhaps not the most efficient, but gets the job done.
Scala arrays offer a lastIndexWhere method which takes a predicate and returns the index of the last element which fulfills the predicate:
val arr = Array("EH1","N", "D", "P", "ER0", "EH1", "N", "TH", "AH0", "S", "IY2", "Z")
val idx = arr.lastIndexWhere(e => e.intersect(Array('0', '1', '2')).size > 0)
and then you call the takeRight method to get the desired result
val res = arr.takeRight(arr.size - idx)

code for finding duplicates in an array, Scala

I'm trying to build a algorithm that can find duplicates in an array, without Using any pre-implemented functions such as "sort" etc.
I have no error but my function does not work… Do you have any idea why? (I'm just starting Scala programming)
def duplicate(s: Array[Int], length: Int): Boolean = {
var i = 0 // start counting at value 0
var j = 0
var result:Boolean = false
var isDupli:Boolean = false
while(j < length && result == false) {
if (s(i) == s(j)) {
isDupli = true
result = true
}
j += 1
}
result
}
var myArray = Array(2,2,2,2)
duplicate(Array(2,2), 2)
I found some code online but people are Using the function sort. My goal is to scroll through the array to find for any duplicates...
Some observations on your code:
You only look at the first (0th) element, and never increment i, so you don't check any of the subsequent elements for duplication.
The length argument is redundant, since we can discover the length of the Array, s, via its .length (or .size) attribute. Using the .length attribute is safer, because it is always valid. For example, duplicate(Array(1, 2, 3, 4, 5, 3), 10) causes an exception (java.lang.ArrayIndexOutOfBoundsException) since the array doesn't have 10 members.
You initialize j to have the same value as i, and then compare s(i) == s(j), so you're always going to get a duplicate on the first element, even if there's no duplication in the array.
You return result (which indicates whether you've found a result), rather than isDupli (which indicates whether you found a duplicate). Fortunately, we only need one of these, since finding a result is the same as finding a duplicate.
Here's another version that fixes these problems, and simplifies some code:
def duplicate(s: Array[Int]): Boolean = {
val length = s.length
var i = 0 // start counting at value 0
var foundDuplicate = false // Type inference means Scala knows this is Boolean
// Loop through each member until we've found a duplicate.
//
// Note that "!foundDuplicate" is the same as "foundDuplicate == false"
while(i < length && !foundDuplicate) {
// Now compare to each of the remaining elements. Start at the element above i.
var j = i + 1
// Loop through each of the remaining elements.
while(j < length && !foundDuplicate) {
// If we find a match, we're done.
if (s(i) == s(j)) {
foundDuplicate = true
}
// Look at the next j
j += 1
}
// Look at the next i
i += 1
}
// Return the result. If we didn't find anything, this will still be false.
foundDuplicate
}
val myArray1 = Array(1, 2, 3, 4, 5, 6, 2, 8, 9)
val myArray2 = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
duplicate(myArray1) // Returns true
duplicate(myArray2) // Returns false
However, while this is perfectly OK procedural code, in Scala we can use a much better functional style. (Procedural code uses vars, while loops, etc. which is frowned upon in Scala.)
import scala.annotation.tailrec
def duplicate(s: Array[Int]): Boolean = {
// Helper function to search the array for matches to element at i
#tailrec // Indicates function is tail recursive.
def matchElement(i: Int): Boolean = {
// Helper function to search for a match in remainder of array.
#tailrec
def matchRem(j: Int): Boolean = {
// If j has reached the end of the array, we had no match.
if(j >= s.length) false
// Otherwise, does this element match the target? Match found.
else if (s(i) == s(j)) true
// Otherwise, look at the next element after j.
else matchRem(j + 1) // Recursive call
}
// If this is the last character of the array, then we can't have a match.
if(i >= s.length - 1) false
// Otherwise did we find a duplicate in the remainder of this array?
else if(matchRem(i + 1)) true
// Otherwise, perform another iteration looking at the next element.
else matchElement(i + 1) // Recursive call
}
// Start the ball rolling by looking at for duplicates of the first character.
matchElement(0)
}
This might look rather complex, at first glance, but note that it doesn't have any var declarations or while loops. Of course, this a roll-your-own solution. There are far simpler methods of achieving this using other Array functions.
In your code the variable isDupli of no use because anyway you are returning result Boolean variable. Also, you are not incrementing variable i. You can use for loop as below:
def duplicate(s: Array[Int], length: Int): Boolean ={
var result:Boolean = false; val r = Range(0,length)
for(i<-r;j<-(i+1) until length; if(s(i)==s(j))) result = true
result
}
In Scala REPL:
scala> duplicate(Array(2,2),2)
res4: Boolean = true
scala> duplicate(Array(2,3),2)
res5: Boolean = false
scala> duplicate(Array(2,3,2),3)
res6: Boolean = true
scala> duplicate(Array(2,3,4),3)
res7: Boolean = false

How to check if an Array of strings is sorted in alphabetical order or not using Kotlin?

I am given a list of strings and I need to see if they are in alphabetical order.
I know I need to use a for loop and check the first character of each string but I don't know how to progress from there.
for (item in array)
println(item[0])
For example ["adam", "ben", "chloe"] should return true.
And likewise for ["ben", "adam", "chloe"] should return false.
UPD: Since Kotlin 1.2 the following is available:
Most efficient variant, creates the smallest amount of intermediate objects:
listOf(1, 2, 3).asSequence().zipWithNext { a, b -> a <= b }.all { it }
Note on efficiency: Creates only two Sequence objects and one function object. Uses Boolean constants as an intermediate value. The final all invocation is inlined as a while loop over the sequence.
Slightly less efficient variant:
listOf(1, 2, 3).asSequence().windowed(2).all { (a, b) -> a <= b }
It's slightly less efficient, as it creates creates intermediate List(a, b) for every element of the original list.
Both of these variants were listed in the answers below by #Billbucket and #AshishChaudhary.
Old answer, for previous versions of Kotlin:
Here is a one liner:
val a = listOf("a", "b", "c")
a.zip(a.drop(1)).all { (a, b) -> a <= b }
// true
Explanation:
a.zip(a.drop(1)) returns pairs of neighbour elements. If in every pair first element is less or equal to the next, array is in order.
If you want to improve performance, you can wrap your array in lazy sequence first. In this case array won't be copied:
a.asSequence().let { it.zip(it.drop(1)).all { (a, b) -> a < b } }
The whole thing is O(N) (single pass through array), which is optimal for this task.
you can use a simple one-liner:
array.zipWithNext { s1, s2 -> s1 <= s2 }.all { it }
Im sure you could do your desired task completely using a for-loop.
However in Kotlin I personally think it would be more idiomatic to do something like this using until:
fun isAlphabetical(stringsArray: Array<String>): Boolean {
if (stringsArray.size < 2) return true
return (1 until stringsArray.size).none { stringsArray[it] <= stringsArray[it - 1] }
}
fun main(args: Array<String>) {
val testCases = arrayOf(arrayOf("adam", "ben", "chloe"), arrayOf("ben", "adam", "chloe"))
for(testCase : Array<String> in testCases){
println("The strings are: ${testCase.joinToString()}")
if (isAlphabetical(testCase)) {
println("Strings are in alphabetical order.\n")
} else {
println("Strings are not in alphabetical order.\n")
}
}
}
Output:
The strings are: adam, ben, chloe
Strings are in alphabetical order.
The strings are: ben, adam, chloe
Strings are not in alphabetical order.
Basically you only compare each element of the array with the previous element (using <=) if the length of the array is more than 1.
A very simple and easy way to accomplish it is by sorting and comparing the original list with the sorted one (two lists are equal when they have the exact same elements in the same order). Since you mentioned you are dealing with an array, you first need to convert it to a list. This solution is not the best in terms of performance (it's O(n log n) and converts the array twice to a list) but it's very readable:
val test = array.asList() == array.asList().sorted()
The full code for your question could be:
println(if (array.asList() == array.asList().sorted()) "Strings are in alphabetical order." else "Strings are not in alphabetical order.")
Another solution:
val list = listOf("a", "b", "c")
list.windowed(2).none { (a, b) -> a > b }
// true
In case you want to compare arbitrary Comparable list:
fun <T : Comparable<T>> isCollectionSortedAsc(list: Collection<T>): Boolean {
return list.zipWithNext { a, b -> a.compareTo(b) == -1 }.all { it }
}
Based on the accepted answer above: https://stackoverflow.com/a/47296632/4919972
Yet another solution :)
data class Result(val isInOrder: Boolean, val lastString: String) {
val toString = when {
isInOrder -> "Strings are in alphabetical order."
else -> "Strings are not in alphabetical order."
}
}
fun Array<String>.isInAlphabeticalOrder() =
this.fold(Result(true, ""), { acc, word -> Result(acc.isInOrder && acc.lastString < word, word) })
fun main(args: Array<String>) {
val test1 = arrayOf("adam", "ben", "chloe")
val test2 = arrayOf("ben", "adam", "chloe")
println(test1.isInAlphabeticalOrder().toString)
println(test2.isInAlphabeticalOrder().toString)
}

how to print Scala user defined Arrays

I tried below code but it ultimately prints 5 zeros after giving the user defined values to array .
the below code takes array of size 5 and gives user defined values
object printarray {
def main(args:Array[String]) {
val arr = new Array[Int](5)
println("the values of array is ")
for(i<-0 to 4) {
val arr = scala.io.StdIn.readInt()
}
arr.foreach(println)
}
}
There are a couple of things that need improvement in the code.
You allocate an array of 5 elements named arr in the scope of the main method, but you also declare an additional value with the same name, arr, inside the for comprehension scope and read an Int into it, which you discard once you exit the for scope. Then, you print the array in the outer scope, which hasn't changed at all.
The first thing you need to make this work, is index into the array instead of creating a new value named arr in the inner scope:
object printarray {
def main(args:Array[String]) {
val arr = new Array[Int](5)
println("the values of array is ")
for (i <- 0 to 4) {
arr(i) = scala.io.StdIn.readInt()
}
arr.foreach(println)
}
}
To improve things further, you use the yield Scala synax to make this more concise:
val arr = for (i <- 0 to 4) yield StdIn.readInt()
This will not return an Array[Int], but an IndexedSeq[Int] with an underlying type of Vector[Int]. If you still want an Array[Int], you'll have to explicitly call toArray:
val arr: Array[Int] = (for (i <- 0 to 4) yield scala.io.StdIn.readInt()).toArray
In your for-loop you are reassigning the variable in every iteration. You can change it to:
for(i <- 0 to 4) {
arr(i) = scala.io.StdIn.readInt()
}
As a side-note, instead of declaring the arr before the loop you can simply do:
val arr = for(i <- 0 to 4) yield scala.io.StdIn.readInt()

can the keyword "foreach" get the array parameter?

I am a beginner of the scala. many concepts aren't clear for me.
I want to ask that if the foreach can get (or control) the array parameter ?
for example:
val array = Array.ofDim[Double](2,6)
I can use for to control the array's parameter, like
for( i <- 0 until 2){
for(j <- 0 until 6){
......... }}
I can use i,j control and get the parameter. Is "foreach" can do that??
(I know foreach can do things without the parameter, but I just want to ask if it can get
the array parameter?)
thank you :)
I'm not exactly sure what you're asking. If you're asking how to loop over the full array item-by-item, then you can do that without nesting for comprehensions. This will print the contents of your 2D array:
for (row <- array; col <- row) println(col)
If you're asking how to loop over all the indices of the array (I think maybe that's what you mean when you say parameter), then you can use the indices property:
for (i <- array.indices; j <- array(i).indices) println(array(i)(j))
If you're just trying to do indexOf across a 2D array, you can probably just reuse the solution for indexOf for 2D Vector in Scala. This is how I'd adapt it to your code:
val array = Array.tabulate(2,6)(_*6+_)
val searchValue = 8
val indices: Option[(Int, Int)] =
(for {
i <- array.indices
j <- array(i).indices
if (array(i)(j) == searchValue)
} yield (i, j)).headOption
If none of the values match, you'll get indices = None. In this case there is a match, so you get indices = Some((1,2)), because 8 is at array(1)(2).
(Note: Unlike indexOf, using a for comprehension does not short-circuit as soon as it finds the solution. If you make the index ranges lazy by calling .iterator, .view or .toStream then you'll get the expected short-circuiting behavior.)
U can use the function [ indexOf(elem: T): Int ] that will return the position
Scala Array

Resources