I have a beginner Julia question regarding generating two types of vectors:
How to I generate a vector consisting out of n of the same elements, without having to type it out manually? For example, how do I generate a vector v consisting out of 7 times the number 5, thus v = [5,5,5,5,5,5,5].
How do I generate a vector with n sequential integers starting at integer x, again without having to type it out manually? For example how do I generate a vector z with 10 sequential integers starting at 1, thus z = [1,2,3,4,5,6,7,8,9,10].
julia> v = fill(5, 7);
julia> #show v;
v = [5, 5, 5, 5, 5, 5, 5]
julia> z = collect(1:10);
julia> #show z;
z = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Note that in the second case, often you can operate on the range 1:10 directly without having to do a collect on it (z = 1:10). 1:10 is a Range type, that works by saving just the starting and ending points, without allocating memory for all 10 values. collect converts that into a full Vector, which allocates memory for each element.
To generate the example: v = repeat([5],7])
To generate the example: z = [1:10;]
Related
I have a matrix that contains lists containing shortest path sequences of an igraph object.
I want to turn this matrix into an igraph.es(edge sequence).
sample:
library(igraph)
data <- data.frame(from =c(1, 2, 3, 4, 5, 1),
to =c(4, 3, 4, 5, 6, 5),
weight=c(0.2,0.1,0.5,0.7,0.8,0.2))
g <- graph.data.frame(data, directed=FALSE)
sp <- sapply(data, function(x){shortest_paths(g, from = x, to = V(g)[x],output = "epath")})
sp is now a matrix. We can subset it with indexing:
x<-sp[[2]][[2]]
will turn x to an igraph::edge_sequence.
I'm looking for an apply command to turn all path_sequences of sp into edge_sequences. Thank you in advance.
EDIT:
I managed to unlist the first layer of the list.
sp<-flatten(sp)
So we just need a simple index.
Can I just use a for loop now?
Something like:
for(i in sp){ result[i]<- sum(E(g)$weight[sp[[i]])}
unfortunately this doesn't give me the desired output..
edit: added current solution
I am dabbling with the Travelling Salesman Problem and am using a solver to calculate the most optimal tour. The output of my linear solver gives me a table with arches in a route, however to plot the tour I require vector with all the locations chained in the right order. Is there an elegant way to chain these arches into a single tour?
One solution would be a series of (nested) joins/matches, however that is not an elegant solution in my opinion.
# output of solver (where i = 'from' and j = 'to')
solution = data.frame(i = c(6, 4, 10, 7, 1, 9, 3, 2, 8, 5),
j = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))
# transformation
??
# required output
tour = c(6, 1, 5, 10, 3, 7, 4, 2, 8, 9)
So the output I am looking for is a single chain of connected arches (from i to j) in the tour.
My current solution uses for loops and match and looks as follows:
# number of cities to visit
nCities = length(solution)
# empty matrix
tour = matrix(0, nCities, 2)
#first location to visit picked manually
tour[1, ] = solution[1, ]
# for loop to find index of next arch in tour
for(k in 2:nCities){
ind = match(tour[k - 1, 2], solution[, 1])
tour[k, ] = solution[ind, ]
}
# output 'tour' is the solution but then sorted.
# I then take only the first column which is the tour
tour = tour[1, ]
However, it looks clunky and as I try to avoid for loops as much as possible I am not to happy with it. Also, my suspicion is that there are more elegant solutions out there, preferably using base R functions.
I can't figure out why seq() can output different classes depending on if decimal points are present in the elements, whereas c() always creates a num vector regardless of presence or absence of decimals.
For example:
seqDec <- seq(1, 2, 0.5) # num vector
cDec <- c(1, 1.5, 2) # num vector
seqInt <- seq(1, 5) # int vector
cInt <- c(1, 2, 3, 4, 5) # num vector
c creates a vector by concatenating the elements you give it. By contrast seq actually constructs a sequence by generating new numbers based on specific parameters.
So in the case of c(1, 2, 4, 5), since the arguments are numeric, so is the result (class(1) is numeric, not integer!). You could generate an integer vector by providing integers:
intvec = c(1L, 2L, 3L, 4L, 5L)
Cumbersome. But possible.
With seq, if you don’t provide a step size (by parameter), the function defaults to generating integral values; in this regard it’s equivalent to the : operator:
intvec = 1 : 5
In fact, if you don’t provide a by or length.out argument, then seq(from, to)internally executes from : to.
I wish to extract an increasing subsequence of a vector, starting from the first element. For example, from this vector:
a = c(2, 5, 4, 0, 1, 6, 8, 7)
...I'd like to return:
res = c(2, 5, 6, 8).
I thought I could use a loop, but I want to avoid it. Another attempt with sort:
a = c(2, 5, 4, 0, 1, 6, 8, 7)
ind = sort(a, index.return = TRUE)$ix
mat = (t(matrix(ind))[rep(1, length(ind)), ] - matrix(ind)[ , rep(1, length(ind))])
mat = ((mat*upper.tri(mat)) > 0) %*% rep(1, length(ind)) == (c(length(ind):1) - 1)
a[ind][mat]
Basically I sort the input vector and check if the indices verify the condition "no indices at the right hand side are lower" which means that there were no greater values beforehand.
But it seems a bit complicated and I wonder if there are easier/quicker solutions, or a pre-built function in R.
Thanks
One possibility would be to find the cumulative maxima of the vector, and then extract unique elements:
unique(cummax(a))
# [1] 2 5 6 8
The other answer is better, but i made this iterative function which works as well. It works by making all consecutive differences > 0
increasing <- function (input_vec) {
while(!all(diff(input_vec) > 0)){
input_vec <- input_vec[c(1,diff(input_vec))>0]
}
input_vec
}
I am looking for an efficient way to simplify a vector of integers as a summary string, in order to format it to fit in a table cell.
For example:
c(1, 2, 3, 4, 6, 8, 9, 10)
should produce
"1-4, 6, 8-10"
This becomes especially useful in cases where printing all elements in the vector would quickly make the table unreadable.
e.g.
c(1:50, 53, 89:120)
should produce
"1-50, 53, 89-120"
You want to group the elements into blocks of consecutive integers.
diff can tell you if two consecutive elements are in the same block,
cumsum can number the blocks
and tapply can extract the first and last element of each block.
x <- c(1:50, 53, 89:120)
y <- tapply( x, c(0,cumsum(diff(x) != 1)), range )
# Format the result
y <- sapply(y, function(u)
if(u[1]==u[2]) u[1]
else paste(u,collapse=":")
)
paste(y, collapse=", ")