I am working on the guide.elm-lang website on the Random example.
I am trying to add a feature that shows you the total number of times you threw the dice, and some stats on how many times you got each face.
To do this I've changed the model to look like this:
type alias Model =
{
die_face : Int,
total_throws : Int,
stats: Array.Array Int
}
and this is what I do to update the model:
{ model |
die_face = face,
total_throws = model.total_throws + 1,
stats = Array.set face ((Array.get face model.stats) + 1) model.stats
}
this throws an error that tells me:
This get call produces:
#Maybe# Int
But (+) only works with #Int# and #Float# values.
Which refers to Array.get not returning a Int but a Maybe and therefore I can't add it to the number 1.
I have tried using lists to achieve the same purpose but since they are not indexed I am not sure what to increment when I map over it. I am thinking of using records to do this and figure out a way to map the record keys to the face Int.
In general my question is. What is a good method to increment an element at index [x] of an Array in elm ? Or if I am just thinking about this wrong, what would be the elm way ?
Array.get returns a Maybe because it has to account for the case where the index is outside the array. The simplest way of getting around that is using Maybe.withDefault with a reasonable default value:
Array.set face (((Array.get face model.stats) |> Maybe.withDefault 0) + 1) model.stats
It might be a good idea to write a helper function for this though, to clean up the code a bit. Something like this:
incrementAt : Int -> Array Int -> Array Int
incrementAt index array =
case Array.get index array of
Just value ->
Array.set index (value + 1) array
Nothing ->
array
You can also use Array.Extra.update if you don't mind the extra dependency.
Related
I have array contain string items in scala , each item contain from prefix + || + double value like below :
var y = Array("Zara||6.0", "Nuha||4.0","Zara||2.0","Zara||0.1")
what I want to Do :
i need sum all double value from above array (y(i).split("\|\|")(1)) But if the prefix the duplicated in the array then I only want sum the max value like below :
for item Zara we have 3 values i want to take the max (in our sample it 6.0)
for item Nuha it unique then i will take it's value (4.0)
the excepted output is (6.0+4.0)=10.0
is there are any way to do it in scala rather than using 2 instead loop ?
Prepare your array: extract prefix and values into tuple. Use foldLeft for aggregate max elem for each prefix, and sum values
val res = y.map(_.split("\\|\\|")).map(arr => (arr(0), arr(1).toDouble))
.foldLeft(Map.empty[String, Double]) { (acc, elem) =>
val value = acc.get(elem._1).map(math.max(_, elem._2)).getOrElse(elem._2)
acc + (elem._1 -> value)
}.values.sum
println(res)
You can do it pretty much in one step (it's three steps technically, but only one specifically addressing your requirement, everything else (split and sum) is kinda a given either way.
y
.iterator
.map(_.split("""\|\|"""))
.groupMapReduce(_.head)(_.last.toDouble)(_ max _)
.values
.sum
Also ... do not use vars. Even if you just putting together a quick sample. Vars are evil, just pretend they do not exist at all ... at least for a while, until you acquire enough of a command of the language to be able to tell the 1% of situations, where you might actually need them. Actually, avoid using Arrays as much as possible too.
I want to calculate the percent change between periods of each element in the "features" array (simply using the array as a grouping of financial time series data to report on). However the way the script is working now, it seems that it wants to calculate the percent change between each element in the array and not FOR each element in the array.
I don't think I've done anything wrong here in how I reference the array elements but I get the feeling there's some sort of 'under the hood' concept about how variables are processed by TV that is causing this issue.
//#version=4
study("My Script")
pct_change(source, period) =>
now = source
then = source[period]
missing_now = na(now)
missing_then = na(then)
if not missing_now and not missing_then
(now - then) / abs(then)
else
missing_now ? 0 : 1
evaluate(sources) =>
s = array.size(sources)
bar_changes = array.new_float()
for i = 0 to 99999
if i < s
source = array.get(sources, i)
array.push(bar_changes, pct_change(source, 1))
continue
else
break
bar_changes
features = array.new_float()
array.push(features, open)
array.push(features, high)
array.push(features, close)
bar_changes = evaluate(features)
plot(pct_change(open, 1))
plot(array.get(bar_changes, 0))
plot(pct_change(high, 1), color=color.aqua)
plot(array.get(bar_changes, 1), color=color.aqua)
plot(pct_change(close, 1), color=color.red)
plot(array.get(bar_changes, 2), color=color.red)
I think you have come across the same problem I'm faced with, and it relates to using history referencing operator [] in connection with setting array element values.
I've boiled it down to a very simple script illustrating the problem
here.
In essence what you are doing in your code is passing array element to a pct_change() function, which uses [] operator, and then use returned result in array.push() to set array element value.
I've experienced weird results when I was trying to experiment with arrays in my scripts as soon as they've been introduced, so I started to dig in order to find the root of the problem. And it came down to the script referenced in the link above. So far I believe that Pine Script still has some bugs when it comes to arrays so we just have to wait until they'll be fixed.
I already flunked an assessment a little while ago but this question is still bugging me. The idea is to add all the elements of a multidimensional array like this: [1,[2,3],4,[5,6,[7]]]] and add them up as if they were all one-line, like 1+2+3+4+5+6+7, without being able to use #flatten. I got about as far as removing all the integers (like 1 and 4) and adding them into its own variable and then trying to reduce(:+) the 2nd level arrays( [2,3], etc), but I can't figure out how to write a loop that will delve deeper into the dimensions, like the [7]. How would one do that?
Code I've tried thus far
def multi_array_sum(arrays)
#need to add up all array elements
num = 0
arr = {}
arrays.each {|int| num = num + int if int.class == Fixnum; arrays.delete(int)}
array.map do |numz|
num = num + numz.reduce(:+)
end
end
I have the following (imperative) algorithm that I want to implement in Haskell:
Given a sequence of pairs [(e0,s0), (e1,s1), (e2,s2),...,(en,sn)], where both "e" and "s" parts are natural numbers not necessarily different, at each time step one element of this sequence is randomly selected, let's say (ei,si), and based in the values of (ei,si), a new element is built and added to the sequence.
How can I implement this efficiently in Haskell? The need for random access would make it bad for lists, while the need for appending one element at a time would make it bad for arrays, as far as I know.
Thanks in advance.
I suggest using either Data.Set or Data.Sequence, depending on what you're needing it for. The latter in particular provides you with logarithmic index lookup (as opposed to linear for lists) and O(1) appending on either end.
"while the need for appending one element at a time would make it bad for arrays" Algorithmically, it seems like you want a dynamic array (aka vector, array list, etc.), which has amortized O(1) time to append an element. I don't know of a Haskell implementation of it off-hand, and it is not a very "functional" data structure, but it is definitely possible to implement it in Haskell in some kind of state monad.
If you know approx how much total elements you will need then you can create an array of such size which is "sparse" at first and then as need you can put elements in it.
Something like below can be used to represent this new array:
data MyArray = MyArray (Array Int Int) Int
(where the last Int represent how many elements are used in the array)
If you really need stop-and-start resizing, you could think about using the simple-rope package along with a StringLike instance for something like Vector. In particular, this might accommodate scenarios where you start out with a large array and are interested in relatively small additions.
That said, adding individual elements into the chunks of the rope may still induce a lot of copying. You will need to try out your specific case, but you should be prepared to use a mutable vector as you may not need pure intermediate results.
If you can build your array in one shot and just need the indexing behavior you describe, something like the following may suffice,
import Data.Array.IArray
test :: Array Int (Int,Int)
test = accumArray (flip const) (0,0) (0,20) [(i, f i) | i <- [0..19]]
where f 0 = (1,0)
f i = let (e,s) = test ! (i `div` 2) in (e*2,s+1)
Taking a note from ivanm, I think Sets are the way to go for this.
import Data.Set as Set
import System.Random (RandomGen, getStdGen)
startSet :: Set (Int, Int)
startSet = Set.fromList [(1,2), (3,4)] -- etc. Whatever the initial set is
-- grow the set by randomly producing "n" elements.
growSet :: (RandomGen g) => g -> Set (Int, Int) -> Int -> (Set (Int, Int), g)
growSet g s n | n <= 0 = (s, g)
| otherwise = growSet g'' s' (n-1)
where s' = Set.insert (x,y) s
((x,_), g') = randElem s g
((_,y), g'') = randElem s g'
randElem :: (RandomGen g) => Set a -> g -> (a, g)
randElem = undefined
main = do
g <- getStdGen
let (grownSet,_) = growSet g startSet 2
print $ grownSet -- or whatever you want to do with it
This assumes that randElem is an efficient, definable method for selecting a random element from a Set. (I asked this SO question regarding efficient implementations of such a method). One thing I realized upon writing up this implementation is that it may not suit your needs, since Sets cannot contain duplicate elements, and my algorithm has no way to give extra weight to pairings that appear multiple times in the list.
I am currently trying to figure out how to design some sort of loop to insert data into an array sequentially. I'm using Javascript in the Unity3D engine.
Basically, I want to store a bunch of coordinate locations in an array. Whenever the user clicks the screen, my script will grab the coordinate location. The problem is, I'm unsure about how to insert this into an array.
How would I check the array's index to make sure if array[0] is taken, then use array[1]? Maybe some sort of For loop or counter?
Thanks
To just add onto the end of an array, just use .push().
var myArray = [];
var coord1 = [12,59];
var coord2 = [87,23];
myArray.push(coord1);
myArray.push(coord2);
myArray, now contains two items (each which is an array of two coordinates).
Now, you wouldn't do it this way if you were just statically declaring everything as I've done here (you could just statically declare the whole array), but I just whipped up this sample to show you how push works to add an item onto the end of an array.
See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push for some reference doc on push.
In case you need to know the array's length when reading the array in the future, you can use the .length attribute.
var lengthOfArray = myArray.length;
Using the .push() method as suggested by jfriend00 is my recommendation too, but to answer your question about how to work out what the next index is you can use the array's length property. Because JavaScript arrays are zero-based The length property will return an integer one higher than the current highest index, so length will also be the index value to use if you want to add another item at the end:
anArray[anArray.length] = someValue; // add to end of array
To get the last element in the array you of course say anArray[anArray.length-1].
Note that for most purposes length will give the number of elements in the array, but I said "one higher than the current highest index" above because JavaScript arrays are quite happy for you to skip indexes:
var myArray = [];
myArray[0] = "something";
myArray[1] = "something else";
myArray[50] = "something else again";
alert(myArray.length); // gives '51'
// accessing any unused indexes will return undefined