What is the difference between ArrayBuffer and Array - arrays

I'm new to scala/java and I have troubles getting the difference between those two.
By reading the scala doc I understood that ArrayBuffer are made to be interactive (append, insert, prepend, etc).
1) What are the fundamental implementation differences?
2) Is there performance variation between those two?

Both Array and ArrayBuffer are mutable, which means that you can modify elements at particular indexes: a(i) = e
ArrayBuffer is resizable, Array isn't. If you append an element to an ArrayBuffer, it gets larger. If you try to append an element to an Array, you get a new array. Therefore to use Arrays efficiently, you must know its size beforehand.
Arrays are implemented on JVM level and are the only non-erased generic type. This means that they are the most efficient way to store sequences of objects – no extra memory overhead, and some operations are implemented as single JVM opcodes.
ArrayBuffer is implemented by having an Array internally, and allocating a new one if needed. Appending is usually fast, unless it hits a limit and resizes the array – but it does it in such a way, that the overall effect is negligible, so don't worry. Prepending is implemented as moving all elements to the right and setting the new one as the 0th element and it's therefore slow. Appending n elements in a loop is efficient (O(n)), prepending them is not (O(n²)).
Arrays are specialized for built-in value types (except Unit), so Array[Int] is going to be much more optimal than ArrayBuffer[Int] – the values won't have to be boxed, therefore using less memory and less indirection. Note that the specialization, as always, works only if the type is monomorphic – Array[T] will be always boxed.

The one other difference is, Array's element created as on when its declared but Array Buffer's elements not created unless you assign values for the first time.
For example. You can write Array1(0)="Stackoverflow" but not ArrayBuffer1(0)="Stackoverflow" for the first time value assignments.
(Array1 = Array variable & ArrayBuffer1 = ArrayBuffer variable)
Because as we know, Array buffers are re-sizable, so elements created when you insert values at the first time and then you can modify/reassign them at the particular element.
Array:
Declaring and assigning values to Int Array.
val favNums= new Array[Int](20)
for(i<-0 to 19){
favNums(i)=i*2
}
favNums.foreach(println)
ArrayBuffer:
Declaring and assigning values to Int ArrayBuffer.
val favNumsArrayBuffer= new ArrayBuffer[Int]
for(j<-0 to 19){
favNumsArrayBuffer.insert(j, (j*2))
//favNumsArrayBuffer++=Array(j*3)
}
favNumsArrayBuffer.foreach(println)
If you include favNumsArrayBuffer(j)=j*2 at the first line in the for loop, It doesn't work. But it works fine if you declare it in 2nd or 3rd line of the loop. Because values assigned already at the first line now you can modify by element index.
This simple one-hour video tutorial explains a lot.
https://youtu.be/DzFt0YkZo8M?t=2005

Use an Array if the length of Array is fixed, and an ArrayBuffer if the length can vary.

Another difference is in term of reference and value equality
Array(1,2) == Array(1,2) // res0: Boolean = false
ArrayBuffer(1, 2) == ArrayBuffer(1,2) // res1: Boolean = true
The reason for the difference is == routes to .equals where Array.equals is implemented using Java's == which compares references
public boolean equals(Object obj) {
return (this == obj);
}
whilst ArrayBuffer.equals compares elements contained by ArrayBuffer using sameElements method
override def equals(o: scala.Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (
o match {
case it: Seq[A] => (it eq this) || (it canEqual this) && sameElements(it)
case _ => false
}
)
Similarly, contains behaves differently
Array(Array(1,2)).contains(Array(1,2)) // res0: Boolean = false
ArrayBuffer(ArrayBuffer(1,2)).contains(ArrayBuffer(1,2)) // res1: Boolean = true

Related

Accessing an array inside an array

I am new to coding in scala and I am curious about something and it has been hard to find an answer for online. I have this array that takes multiple arguments of different types (:Any)
val arguments= Array("Monday",10,20,Array("test","test2"), if(4 == 4){ "true"})
I iterated and printed the content inside of it. Everything prints properly except the Array at index 3. I get the object memory address I believe, which is understandable-- same thing with Java would happen. But I am curious, how would you access it?
I tried saving the value of arguments(3) in an array (val arr:Array[String] = arguments(3)) but it didn't work because there is a type mismatch (any != Array[String])
Any tips? It might be a gap in my understanding of functional programming.
What you are iterating through is an Array[Any], so you are able to perform functions that are available to an Any type. You can access the items in your array using pattern matching, which uses the unapply methods under the hood to see if it can turn your Any into something more specific:
val arguments= Array("Monday",10,20,Array("test","test2"), if(4 == 4){ "true"})
arguments foreach { arg =>
arg match {
case a:Array[String] => println(s"This is the array: ${a.mkString(",")}, and I can do array functions ${a.contains("test")}")
case _ => println(s"Otherwise I have this: $arg")
}
}
// stdout:
// Otherwise I have this: Monday
// Otherwise I have this: 10
// Otherwise I have this: 20
// This is the array: test,test2, and I can do array functions true
// Otherwise I have this: true

swift: extend array comparability

In swift 4 arrays are automatically comparable - but they check each element sequentially. Does element 1 match element 1, element 2 match element 2, etc.? - which is probably good standard behaviour.
But I'd like to extend / change this behaviour for a certain type Interval, so it doesn't matter what the order is of the elements, as long as the contents of the two arrays match. i.e. if both the arrays are sorted and match (using the original behaviour) then that should trigger comparable.
The trouble is, by defining my new behaviour, I 'override' and lose the existing behaviour (which I'd like ideally to keep so I can test once both arrays are sorted) - and so I get a warning 'All paths through this function will call itself'. Any ideas how to solve please
extension Array where Element == Interval {
static func == (lhs: [Interval], rhs: [Interval]) -> Bool {
return lhs.sorted() == rhs.sorted()
}
}
First make Interval conform to Hashable. Now you can coerce the arrays to Sets and compare for equality without order mattering.

How to get a correct array hashcode in scala?

What is the suitable way to compute hashCode of an Array that depends on its content?
Array.hashCode is for the array instance:
val h = a.hashCode
println(h == Array(1,2).hashCode) // false
a(0) = 42
println(h == a.hashCode) // true
Note: It'd be better to avoid copying the whole array, to a List for example, prior to computing the hashCode
Why I ask: I use an Array in a class (as a private field) because lookup time is critical, and its content is relevant to compute the hashCode of the class
from https://issues.scala-lang.org/browse/SI-1607, it says that the hashCode of Array is the hashCode from java, as scala Array are java Array. And scala could not changed it.
But it also says that scala has a suitable hashCode method in WrappedArray.
Thus:
val a = Array(1,2)
val h = a.toSeq.hashCode // wrapped it in a WrappedArray - no copy
println(h == Array(1,2).toSeq.hashCode) // true
a(0) = 42
println(h == a.toSeq.hashCode) // false
You can also use java.util.Arrays.hashCode(a), it's likely to be faster than a.toSeq.hashCode (since WrappedArray seems to inherit a non-array-specific implementation).
You can use the MurmurHash3 algorithm directly.
import scala.util.hashing.MurmurHash3
MurmurHash3.orderedHash(Array(1,2)))

Array is filled with undefined values (Erlang)

Updated Question; Original below.
I am trying to create an array which represents a grid of cells, which have tuples containing the walls they are surrounded by.
I have come up with this:
rooms(Array) ->
Size = array:size(Array),
if
Size == ?HSIZE * ?VSIZE ->
Array;
true ->
HFactor = Size rem ?VSIZE,
VFactor = Size div ?HSIZE,
Room = {1+HFactor+11*VFactor,
7+HFactor+11*VFactor,
12+HFactor+11*VFactor,
6+HFactor+11*VFactor},
rooms(array:set(Size, Room, Array))
end.
When I run this with rooms(array:new()). I get the following array back:
{array,25,100,undefined,
{{{1,7,12,6},
{2,8,13,7},
{3,9,14,8},
{4,10,15,9},
{5,11,16,10},
{12,18,23,17},
{13,19,24,18},
{14,20,25,19},
{15,21,26,20},
{16,22,27,21}},
{{23,29,34,28},
{24,30,35,29},
{25,31,36,30},
{26,32,37,31},
{27,33,38,32},
{34,40,45,39},
{35,41,46,40},
{36,42,47,41},
{37,43,48,42},
{38,44,49,43}},
{{45,51,56,50},
{46,52,57,51},
{47,53,58,52},
{48,54,59,53},
{49,55,60,54},
undefined,undefined,undefined,undefined,undefined},
10,10,10,10,10,10,10,10}}
Which is quite close to the desired result, but there are two things I can't quite put my finger on (The numbers are correct). Why does it look like it is split up into multiple subarrays? What are those undefineds and 10's doing there? These are mostly due to my lack of erlang knowledge, because array:get produces the expected results, but I couldn't find anything which explains where they come from.
Original Question
rooms(Array) ->
Size = array:size(Array),
if
Size == 5 ->
Array;
Size rem 5 == 0 ->
rooms(array:set(Size, array:new(), Array));
true ->
In_Array = array:get(array:size(Array), Array),
In_Size = array:size(In_Array),
Room = {1+In_Size+11*In_Size,
7+In_Size+11*In_Size,
12+In_Size+11*In_Size,
6+In_Size+11*In_Size},
New_In = array:set(In_Size, Room, In_Array),
rooms(array:set(Size, New_In, Array))
end.
I call it with rooms(array:new()). but the result is
** exception error: bad argument
in function array:size/1 (array.erl, line 317)
in call from framework_kamer:rooms/1 (framework_kamer.erl, line 195)
Which makes sense because In_Array is not an array, but undefined. However, I can't figure out why.
Side question, is there an easier/cleaner/better way to do this?
You are (in the second call of the recursion) trying
In_Array = array:get(array:size(Array), Array),
As array is zero-indexed this will always fail, as the access will be always be off by one. Change this line to
In_Array = array:get(array:size(Array) - 1, Array),
and you are fine.
A few comments on your code:
Conventional variable naming in Erlang would be CamelCase without underscores (i.e. InArray)
Expressing a 2-dimensional array as nested arrays is almost never a good idea. Linearalise it by writing simple wrappers that recalculate a one-dimensional index from x and y as index = y * max_x + x.

Is it sensible to use AS3 Vectors for class instances?

Here is a simple code :
var a:Array = new Array( ins0, ins1, ins2, ins3,...., ins10000) ;
findIns( ins1500) ;
function findIns( ins:SomeInstance ) {
for ( var i = 0 ; i< a.length ; i++) {
if ( a[i] == ins ) {
trace ( "FOUND IT");
break;
}
}
}
In the above code there is NO "int" or "string". They are instances of some complex class. So is it sensible to use Vectors in place of arrays in this case.
In my opinion it should be sensible, because instances are "numerical-memory-locations" afterall ?
If the content of the array are all instances of the same class, then yes Vector will definitely performs better than Array.
See the documentation for more information:
Performance: array element access and iteration are much faster when using a Vector instance than they are when using an Array.
Type safety: in strict mode the compiler can identify data type errors. Examples of data type errors include assigning a value of the incorrect data type to a Vector or expecting the wrong data type when reading a value from a Vector. Note, however, that when using the push() method or unshift() method to add values to a Vector, the arguments' data types are not checked at compile time. Instead, they are checked at run time.
Reliability: runtime range checking (or fixed-length checking) increases reliability significantly over Arrays.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Vector.html
Yes, you are right. What gets stored inside the vector is a reference to your object, not your object itself. You can check that doing the following:
var ref:yourType = a[0];
a[0] = someOtherObjectInstance;
trace(ref.toString());
You will find that ref still points to your original object.

Resources