Looping through keys in Map() object - pari-gp

I'm working with Map() and need an efficient method to loop through all the keys.
Specifically the keys are non matrices, and the image is a t_List of real vectors.
My current method is to turn the Map into a matrix and loop through like below
M = Map();
...\\fill up the map with stuff
matM = Mat(M);
for(i=1, matsize(M)[1],
L = matM[i,2];
\\ proceed to do stuff with L
);
However my understanding is that matM will create a copy of the data inside M, which I'd like to avoid if possible. My only other thought is to create a supplementary list of the ideals as the Map is filled, and then to iterate through that.
Is there a better way to handle this?

You can loop the map using a foreach().
{
foreach(M, item,
my(key = item[1][1]);
my(value = item[1][2]);
print(Str(key, ": ", value));
);
}
It looks a little bit weird because the variable item contains a vector whose first position it's another vector with the key and the value.
If you're going to use it often you could define a function like this:
foreachMap(M, expr) = foreach(M, item, expr(item[1][1], item[1][2]));
lambda = (key, value) -> print(Str(key, ": ", value));
foreachMap(M, lambda);

Related

R function to reverse a survey item produces NULL

I'm still new to writing my own functions. As an exercise and because I use it alot, I want to write a flexible function to easily reverse survey response scales. This is what I came up with:
rev_scale = function(var, new_var, scale){
for (i in 1:length(abs(var))){
new_var[i] = scale-abs(var[i])+1
}
}
Info on code
var = variable I want to reverse.
new_var = new column with the reversed variable
scale = how many points in the scale (eg. 5 for a 5-point scale)
The reason why I use 'abs' instead of just 'var' is that some dataframes also return value-labels, and I only want the values in this function.
Question
When applying this new function on a variable, R returns "NULL". However, if I run the for-loop separately, with the arguments 'imputed', my new variable is properly reversed.
Any ideas on what is happening here?
Thanks in advance!
### Example of the (working) for-loop with arguments 'imputed' ###
df <- data.frame(matrix(ncol = 1, nrow = 4))
df$var = c(1,2,3,4)
for (i in 1:length(abs(df$var))){
df$var_rev[i] = 4-abs(df$var[i])+1
}
df$var_rev
OUTPUT:
[1] 4 3 2 1
R does not use reference-variables (think pointers)*. So your new_var outside of your function does not get updated when refered to inside a function. Instead, R creates a new copy of new_var and updates that.
You should instead return the new value from your function. I.e.
rev_scale = function(var, scale){
res <- vector('numeric', length(var))
for (i in 1:length(abs(var))){
res[i] = scale-abs(var[i])+1
}
return(res)
}
Also note that I have removed new_var from the function's arguments. In other words, I have completely separated the functions input-arguments from its output.
The reason you get a NULL from the function is that in R, all functions returns somethings. If not specified, the function will return the last value of the last statement, except when the last statement is a control structure (ifs, loops) - then it defaults to a NULL.
* There are a couple of exceptions and work-arounds, but I will not go into that here.
Edit:
As benimwolfspelz noted, you do not need to explicitly iterate over each element in var, as R does this implicitly. Your entire function could be reduced to:
rev_scale = function(var, scale) {
scale-abs(var)+1
}
Secondly, in your for-loop, your can simplify length(abs(var)) to length(var) as abs(var) does not change the length of the vector.

Turn multiple 2-dimensional arrays into one 3-dimensional array

I'm rather new to R and there's probably a really easy way to do this, but I can not figure this out for the life of me. I am trying to convert a mutli-layer TIF file into a multi-channel TIF file and to do that I need to basically turn a list of multiple 2-dimensional arrays into one 3-dimensional array.
I attempted to simply split up the 9 different arrays in the list, create a new list with 3 dimensions and insert the arrays into the new list, but it keeps telling me that there is a "wrong number of subscripts".
multiChannelFile = array(c(960, 1280, 9))
for (row in 1:960) {
for (column in 1:1280) {
for (channel in 1:9) {
multiChannelFile[row, column, channel] = tifFile[channel][[1]][row, column]
}
}
}
You can use simplify2array():
multiChannelFile <- simplify2array(tifFile)
And of course, as soon as I posted this question, I figured it out.
Changing multiChannelFile = array(c(960, 1280, 9)) to multiChannelFile = array(dim = c(960, 1280, 9)) did the trick.
You can blend the list to a vector by unlist() and reset the dimension.
array(unlist(tifFile), dim = c(dim(tifFile[[1]]), length(tifFile)))

Getting a function to return the results of a chi squared test [duplicate]

This question already has answers here:
How to assign from a function which returns more than one value?
(16 answers)
Closed 6 years ago.
How can I return multiple objects in an R function? In Java, I would make a Class, maybe Person which has some private variables and encapsulates, maybe, height, age, etc.
But in R, I need to pass around groups of data. For example, how can I make an R function return both an list of characters and an integer?
Unlike many other languages, R functions don't return multiple objects in the strict sense. The most general way to handle this is to return a list object. So if you have an integer foo and a vector of strings bar in your function, you could create a list that combines these items:
foo <- 12
bar <- c("a", "b", "e")
newList <- list("integer" = foo, "names" = bar)
Then return this list.
After calling your function, you can then access each of these with newList$integer or newList$names.
Other object types might work better for various purposes, but the list object is a good way to get started.
Similarly in Java, you can create a S4 class in R that encapsulates your information:
setClass(Class="Person",
representation(
height="numeric",
age="numeric"
)
)
Then your function can return an instance of this class:
myFunction = function(age=28, height=176){
return(new("Person",
age=age,
height=height))
}
and you can access your information:
aPerson = myFunction()
aPerson#age
aPerson#height
Is something along these lines what you are looking for?
x1 = function(x){
mu = mean(x)
l1 = list(s1=table(x),std=sd(x))
return(list(l1,mu))
}
library(Ecdat)
data(Fair)
x1(Fair$age)
You can also use super-assignment.
Rather than "<-" type "<<-". The function will recursively and repeatedly search one functional level higher for an object of that name. If it can't find one, it will create one on the global level.
You could use for() with assign() to create many objects.
See the example from assign():
for(i in 1:6) { #-- Create objects 'r.1', 'r.2', ... 'r.6' --
nam <- paste("r", i, sep = ".")
assign(nam, 1:i)
Looking the new objects
ls(pattern = "^r..$")
One way to handle this is to put the information as an attribute on the primary one. I must stress, I really think this is the appropriate thing to do only when the two pieces of information are related such that one has information about the other.
For example, I sometimes stash the name of "crucial variables" or variables that have been significantly modified by storing a list of variable names as an attribute on the data frame:
attr(my.DF, 'Modified.Variables') <- DVs.For.Analysis$Names.of.Modified.Vars
return(my.DF)
This allows me to store a list of variable names with the data frame itself.

iterating through a multidimensional array using CartesianRange in julia

I want to retrieve all the elements along the last dimension of an N-dimensional array A. That is, if idx is an (N-1) dimensional tuple, I want A[idx...,:]. I've figured out how to use CartesianRange for this, and it works as shown below
A = rand(2,3,4)
for idx in CartesianRange(size(A)[1:end-1])
i = zeros(Int, length(idx))
[i[bdx] = idx[bdx] for bdx in 1:length(idx)]
#show(A[i...,:])
end
However, there must be an easier way to create the index i shown above . Splatting idx does not work - what am I doing wrong?
You can just index directly with the CartesianIndex that gets generated from the CartesianRange!
julia> for idx in CartesianRange(size(A)[1:end-1])
#show(A[idx,:])
end
A[idx,:] = [0.0334735,0.216738,0.941401,0.973918]
A[idx,:] = [0.842384,0.236736,0.103348,0.729471]
A[idx,:] = [0.056548,0.283617,0.504253,0.718918]
A[idx,:] = [0.551649,0.55043,0.126092,0.259216]
A[idx,:] = [0.65623,0.738998,0.781989,0.160111]
A[idx,:] = [0.177955,0.971617,0.942002,0.210386]
The other recommendation I'd have here is to use the un-exported Base.front function to extract the leading dimensions from size(A) instead of indexing into it. Working with tuples in a type-stable way like this can be a little tricky, but they're really fast once you get the hang of it.
It's also worth noting that Julia's arrays are column-major, so accessing the trailing dimension like this is going to be much slower than grabbing the columns.

Creating a vector in MATLAB with a pattern

How do I create a vector like this:
a = [a_1;a_2;...,a_n];
aNew = [a;a.^2;a.^3;...;a.^T].
Is it possible to create aNew without a loop?
So you want different powers of a, all strung out into a vector? I would create an array, where each column of the array is a different power of a. Then string it out into a vector. Something like this...
aNew = bsxfun(#power,a,1:T);
aNew = aNew(:);
This does what you want, in a simple, efficient way. bsxfun is a more efficient way of writing the expansion than are other methods, such as repmat, ndgrid and meshgrid.
The code I wrote does assume that a is a column vector, as you have constructed it.
The idea is to use meshgrid to create two arrays of size n x T:
[n_mesh, t_mesh] = meshgrid(a, 1:T);
Now n_mesh is an array where each row is a duplicate of a, and t_mesh is an array where each column is 1:T.
Now you can use an element-wise operation on them to create what you need:
aNew = n_mesh .^ t_mesh;

Resources