Accessing R list elements through function parameters - list

I have an R list which looks as follows
> str(prices)
List of 4
$ ID : int 102894616
$ delay: int 8
$ 47973 :List of 12
..$ id : int 47973
..$ index : int 2
..$ matched: num 5817
$ 47972 :List of 12
..
Clearly, I can access any element by e.g. prices$"47973"$id.
However, how would I write a function which parametrises the access to that list? For example an access function with signature:
access <- function(index1, index2) { .. }
Which can be used as follows:
> access("47973", "matched")
5817
This seems very trivial but I fail to write such a function. Thanks for any pointers.

Using '[[' instead of '$' seems to work:
prices <- list(
`47973` = list( id = 1, matched = 2))
access <- function(index1, index2) prices[[index1]][[index2]]
access("47973","matched")
As to why this works instead of:
access <- function(index1, index2) prices$index1$index2 (which I assume is what you tried?) it's because here index1 and index2 are not evaluated. That is, it searches the list for an element called index1 instead of what this object evaluates to.

You can take advantage of the fact that [[ accepts a vector, used recursively:
prices <- list(
`47973` = list( id = 1, matched = 2))
prices[[c("47973", "matched")]]
# 2

Related

How to take specific number of input in python

How do I take a specific number of input in python. Say, if I only want to insert 5 elements in a list then how can I do that?
I tried to do it but couldn't figure out how.
In the first line I want to take an integer which will be the size of the list.
Second line will consist 5 elements separated by a space like this:
5
1 2 3 4 5
Thanks in advance.
count = int(raw_input("Number of elements:"))
data = raw_input("Data: ")
result = data.split(sep=" ", maxsplit=count)
if len(result) < count:
print("Too few elements")
You can also wrap int(input("Number of elements:")) in try/except to ensure that first input is actually int.
p.s. here is helpful q/a how to loop until correct input.
Input :-
5
1 2 3 4 5
then, use the below code :
n = int(input()) # Number of elements
List = list ( map ( int, input().split(" ") ) )
Takes the space separated input as list of integers. Number of elements count is not necessary here.
You can get the size of the List by len(List) .
Here list is a keyword for generating a List.
Or you may use an alternative :
n = int(input()) # Number of elements
List = [ int(elem) for elem in input().split(" ") ]
If you want it as List of strings, then use :
List = list( input().split(" ") )
or
s = input() # default input is string by using input() function in python 2.7+
List = list( s.split(" ") )
Or
List = [ elem for elem in input().split(" ") ]
Number of elements count is necessary while using a loop for receiving input in a new line ,then
Let the Input be like :
5
1
2
3
4
5
The modified code will be:-
n = int(input())
List = [ ] #declare an Empty list
for i in range(n):
elem = int(input())
List.append ( elem )
For Earlier version of python , use raw_input ( ) instead of input ( ), which receives default input as String.

How to properly manipulate a string column in a data frame in R?

I have a data.frame with a string column that contains periods e.g "a.b.c.X". I want to split out the string by periods and retain the third segment e.g. "c" in the example given. Here is what I'm doing.
> df = data.frame(v=c("a.b.a.X", "a.b.b.X", "a.b.c.X"), b=seq(1,3))
> df
v b
1 a.b.a.X 1
2 a.b.b.X 2
3 a.b.c.X 3
And what I want is
> df = data.frame(v=c("a.b.a.X", "a.b.b.X", "a.b.c.X"), b=seq(1,3))
> df
v b
1 a 1
2 b 2
3 c 3
I'm attempting to use within, but I'm getting strange results. The value in the first row in the first column is being repeated.
> get = function(x) { unlist(strsplit(x, "\\."))[3] }
> within(df, v <- get(as.character(v)))
v b
1 a 1
2 a 2
3 a 3
What is the best practice for doing this? What am I doing wrong?
Update:
Here is the solution I used from #agstudy's answer:
> df = data.frame(v=c("a.b.a.X", "a.b.b.X", "a.b.c.X"), b=seq(1,3))
> get = function(x) gsub(".*?[.].*?[.](.*?)[.].*", '\\1', x)
> within(df, v <- get(v))
v b
1 a 1
2 b 2
3 c 3
Using some regular expression you can do :
gsub(".*?[.].*?[.](.*?)[.].*", '\\1', df$v)
[1] "a" "b" "c"
Or more concise:
gsub("(.*?[.]){2}(.*?)[.].*", '\\2', v)
The problem is not with within but with your get function. It returns a single character ("a") which gets recycled when added to your data.frame. Your code should look like this:
get.third <- function(x) sapply(strsplit(x, "\\."), `[[`, 3)
within(df, v <- get.third(as.character(v)))
Here is one possible solution:
df[, "v"] <- do.call(rbind, strsplit(as.character(df[, "v"]), "\\."))[, 3]
## > df
## v b
## 1 a 1
## 2 b 2
## 3 c 3
The answer to "what am I doing wrong" is that the bit of code that you thought was extracting the third element of each split string was actually putting all the elements of all your strings in a single vector, and then returning the third element of that:
get = function(x) {
splits = strsplit(x, "\\.")
print("All the elements: ")
print(unlist(splits))
print("The third element:")
print(unlist(splits)[3])
# What you actually wanted:
third_chars = sapply(splits, function (x) x[3])
}
within(df, v2 <- get(as.character(v)))

Function to subset dataframe using pattern list argument

I have a pattern list
patternlist <- list('one' = paste(c('a','b','c'),collapse="|"), 'two' = paste(1:5,collapse="|"), 'three' = paste(c('k','l','m'),collapse="|"))
that I want to select from to extract rows from a data frame
dataframez <- data.frame('letters' = c('a','b','c'), 'numbers' = 1:3, 'otherletters' = c('k','l','m'))
with this function
pattern.record <- function(x, column="letters", value="one")
{
if (column %in% names(x))
{
result <- x[grep(patternlist$value, x$column, ignore.case=T),]
}
else
{
result <- NA
}
return(result)
}
oddly enough, I get an error when I run it:
> pattern.record(dataframez)
Error in grep(patternlist$value, x$column, ignore.case = T) :
invalid 'pattern' argument
The problem is your use of the `$` operator.
In your function, it is looking a column \ named element called column
It is far simpler here to use `[[`
Then x[[column]] uses what column is defined as, not column as a name.
The relevant lines in ?`$` are
Both [[ and $ select a single element of the list. The main difference is that $ does not allow computed indices, whereas [[ does. x$name is equivalent to x[["name", exact = FALSE]]. Also, the partial matching behavior of [[ can be controlled using the exact argument.
You are trying to use value and column as computed indices (i.e. computing what value and column are defined as), thus you need `[[`.
The function becomes
pattern.record <- function(x, column="letters", value="one", pattern_list)
{
if (column %in% names(x))
{
result <- x[grep(pattern_list[[value]], x[[column]], ignore.case=T),]
}
else
{
result <- NA
}
return(result)
}
pattern.record(dataframez, patternlist = pattern_list)
## letters numbers otherletters
## 1 a 1 k
## 2 b 2 l
## 3 c 3 m
note that I've also added an argumentpattern_list so it does not depend on an object named patternlist existing somewhere in the parent environments (in your case the global environment.

Inserting elements in an R list

I want to store a few entries in a "dictionary" so that I can retreive them by name. I can form something like that indirectly like this:
> a = list(c(1,2),c(9,9,0,0))
> names(a) = c("first","second")
> a
$first
[1] 1 2
$second
[1] 9 9 0 0
However, I can't do the same thing by simply inserting them by name like this:
> a=list()
> a["first"] = c(1,2)
Warning message:
In a["first"] = c(1, 2) :
number of items to replace is not a multiple of replacement length
> a
$first
[1] 1
Why is this so, and what syntax should I use to insert objects like vectors or matrices by name into a list?
Your problem is that you are using [ rather than [[. This should work:
a[['first']] <- c(1,2)
as should this:
a$first <- c(1,2)
Remember, [ gives you a sublist, while [[ accesses specific elements.
You got one good answer. Here's an equivalent answer:
a=list()
a["first"] = list(c(1,2))
a
# $first
# [1] 1 2
So to expand on joran's perfectly fine answer, you are really using [<- as a function, and it both gives (via [) and receives (via[<-) lists.
Just because a function returns something is not a promise that it will set something.

How to add variable key/value pair to list object?

I have two variables, key and value, and I want to add them as a key/value pair to a list:
key = "width"
value = 32
mylist = list()
mylist$key = value
The result is this:
mylist
# $key
# [1] 32
But I would like this instead:
mylist
# $width
# [1] 32
How can I do this?
R lists can be thought of as hashes- vectors of objects that can be accessed by name. Using this approach you can add a new entry to the list like so:
key <- "width"
value <- 32
mylist <- list()
mylist[[ key ]] <- value
Here we use the string stored in the variable key to access a position in the list much like using the value stored in a loop variable i to access a vector through:
vector[ i ]
The result is:
myList
$width
[1] 32
The setNames() built-in function makes it easy to create a hash from given key and value lists. (Thanks to Nick K for the better suggestion.)
Usage: hh <- setNames(as.list(values), keys)
Example:
players <- c("bob", "tom", "tim", "tony", "tiny", "hubert", "herbert")
rankings <- c(0.2027, 0.2187, 0.0378, 0.3334, 0.0161, 0.0555, 0.1357)
league <- setNames(as.list(rankings), players)
Then accessing the values through the keys is easy:
league$bob
[1] 0.2027
league$hubert
[1] 0.0555
List elements in R can be named. So in your case just do
> mylist = list()
> mylist$width = value
When R encounters this code
> l$somename=something
where l is a list. It appends to a list an element something, and names it with name somename. It is then can be accessed by using
> l[["somename"]]
or
> l$somename
The name can be changed with command names:
> names(l)[names(l)=="somename"] <- "othername"
Or if you now the position of the element in the list by:
> names(l)[1] <- "someothername"
We can use R's list data structure to store data in the form of key-value pair.
Syntax:
ObjectName<-list("key"= value)
Example:
mylist<-list("width"=32)
also, refer example: "https://github.com/WinVector/zmPDSwR/blob/master/Statlog/GCDSteps.R"