将向量列表转换为列表列表。

huangapple go评论76阅读模式
英文:

List of vectors to list of lists

问题

我有一个这样结构化的列表:

x <- list(id = c("a", "b"),
value = c(1,2),
othervalue = c(3,4)
)


我需要将这个列表转换为如下结构的列表:

y <- list(a = list(value = 1, othervalue = 3),
b = list(value = 2, othervalue = 4)
)


你会如何做这个?

_____

编辑:

我遇到了一个更复杂版本的问题:

这里输出中有一种嵌套列表。

x <- list(id = c("a", "b", "a"), key = c("foo", "foo", "bar"), value = c(1, 2, 3))

y <- list(a = list(foo = 1, bar = 2), b = list(foo = 3))


根据当前的回答,结果是:

$a
$a$key
[1] "foo"

$a$value
[1] 1

$b
$b$key
[1] "foo"

$b$value
[1] 2

$a
$a$key
[1] "bar"

$a$value
[1] 3


<details>
<summary>英文:</summary>

I have a list structured this way:

x <- list(id = c("a", "b"),
value = c(1,2),
othervalue = c(3,4)
)


I need to transform the list to this structure like this:

y <- list(a = list(value = 1, othervalue = 3),
b = list(value = 2, othervalue = 4)
)


How would you do this ?


_____

Edit:

I stumbled upon a more advanced version of this problem:

Here there is some kind of nested list in the output.


x <- list(id = c("a", "b", "a"), key = c("foo", "foo", "bar"), value = c(1, 2, 3))


to

y <- list(a = list(foo = 1, bar = 2), b = list(foo = 3))


With the current answers, the result is:

$a
$a$key
[1] "foo"

$a$value
[1] 1

$b
$b$key
[1] "foo"

$b$value
[1] 2

$a
$a$key
[1] "bar"

$a$value
[1] 3


</details>


# 答案1
**得分**: 7

You can use `list` in `Map` with `do.call`.

```R
z <- setNames(do.call(Map, c(list, x[-1])), x[[1]])

identical(z, y)
#[1] TRUE

The same but using pipes:

z <- c(list, x[-1]) |>
       do.call(what=Map) |>
       setNames(x[[1]])

Benchmark

x <- list(id = c("a", "b"), value = c(1,2), othervalue = c(3,4) )

bench::mark(purr = purrr::transpose(x[-1], .names = x[[1]]), #@Ma&#235;l
            lapplySplit = lapply(split(as.data.frame(x)[-1], x$id), c), #@Allan Cameron
            Map = setNames(do.call(Map, c(list, x[-1])), x[[1]]) ) #@GKi

# expression       min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc
#  &lt;bch:expr&gt;  &lt;bch:tm&gt; &lt;bch:tm&gt;     &lt;dbl&gt; &lt;bch:byt&gt;    &lt;dbl&gt; &lt;int&gt; &lt;dbl&gt;
#1 purr          2.51ms   2.64ms      372.    3.69MB     34.2   152    14
#2 lapplySplit 461.77&#181;s 490.48&#181;s     2018.  102.21KB     52.0   892    23
#3 Map          14.13&#181;s   15.9&#181;s    61557.    3.06KB     80.1  9987    13

Map is in this case about 30 times faster and allocates much less memory compared to lapplySplit the second.

And with the dataset from @s_baldur:

x <- list(id = c(letters, LETTERS), value = 1:52, othervalue = (1:52 + 100))
bench::mark(check=FALSE,
purr = purrr::transpose(x[-1], .names = x[[1]]), #@Ma&#235;l
lapplySplit = lapply(split(as.data.frame(x)[-1], x$id), c), #@Allan Cameron
Map = setNames(do.call(Map, c(list, x[-1])), x[[1]]) ) #@GKi
#  expression       min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc
#  &lt;bch:expr&gt;  &lt;bch:tm&gt; &lt;bch:tm&gt;     &lt;dbl&gt; &lt;bch:byt&gt;    &lt;dbl&gt; &lt;int&gt; &lt;dbl&gt;
#1 purr           2.5ms   2.59ms      385.    3.69MB     33.9   159    14
#2 lapplySplit   2.43ms   2.51ms      391.  137.21KB     68.3   149    26
#3 Map          50.98&#181;s  61.06&#181;s    15717.    3.51KB     72.5  6506    30

For the updated question use maybe:

lapply(split(setNames(x$value, x$key), x$id), as.list)

But is there a need for a list? If not then use maybe:

split(setNames(x$value, x$key), x$id)
英文:

You can use list in Map with do.call.

z &lt;- setNames(do.call(Map, c(list, x[-1])), x[[1]])

identical(z, y)
#[1] TRUE

The same but using pipes:

z &lt;- c(list, x[-1]) |&gt;
       do.call(what=Map) |&gt;
       setNames(x[[1]])

Benchmark

x &lt;- list(id = c(&quot;a&quot;, &quot;b&quot;), value = c(1,2), othervalue = c(3,4) )

bench::mark(purr = purrr::transpose(x[-1], .names = x[[1]]), #@Ma&#235;l
            lapplySplit = lapply(split(as.data.frame(x)[-1], x$id), c), #@Allan Cameron
            Map = setNames(do.call(Map, c(list, x[-1])), x[[1]]) ) #@GKi

# expression       min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc
#  &lt;bch:expr&gt;  &lt;bch:tm&gt; &lt;bch:tm&gt;     &lt;dbl&gt; &lt;bch:byt&gt;    &lt;dbl&gt; &lt;int&gt; &lt;dbl&gt;
#1 purr          2.51ms   2.64ms      372.    3.69MB     34.2   152    14
#2 lapplySplit 461.77&#181;s 490.48&#181;s     2018.  102.21KB     52.0   892    23
#3 Map          14.13&#181;s   15.9&#181;s    61557.    3.06KB     80.1  9987    13

Map is in this case about 30 times faster and allocates mutch less memory compared to lapplySplit the second.
And with the dataset from @s_baldur:

x &lt;- list(id = c(letters, LETTERS), value = 1:52, othervalue = (1:52 + 100))
bench::mark(check=FALSE,
purr = purrr::transpose(x[-1], .names = x[[1]]), #@Ma&#235;l
lapplySplit = lapply(split(as.data.frame(x)[-1], x$id), c), #@Allan Cameron
Map = setNames(do.call(Map, c(list, x[-1])), x[[1]]) ) #@GKi
#  expression       min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc
#  &lt;bch:expr&gt;  &lt;bch:tm&gt; &lt;bch:tm&gt;     &lt;dbl&gt; &lt;bch:byt&gt;    &lt;dbl&gt; &lt;int&gt; &lt;dbl&gt;
#1 purr           2.5ms   2.59ms      385.    3.69MB     33.9   159    14
#2 lapplySplit   2.43ms   2.51ms      391.  137.21KB     68.3   149    26
#3 Map          50.98&#181;s  61.06&#181;s    15717.    3.51KB     72.5  6506    30

For the updated question use maybe:

lapply(split(setNames(x$value, x$key), x$id), as.list)

But is there a need for a list? If not then use maybe:

split(setNames(x$value, x$key), x$id)

答案2

得分: 4

以下是您要翻译的内容:

你可以执行以下操作

lapply(split(as.data.frame(x)[-1], x$id), c)
#&gt; $a
#&gt; $a$value
#&gt; [1] 1
#&gt; 
#&gt; $a$othervalue
#&gt; [1] 3
#&gt; 
#&gt; 
#&gt; $b
#&gt; $b$value
#&gt; [1] 2
#&gt; 
#&gt; $b$othervalue
#&gt; [1] 4

这与 y 完全相同:

identical(lapply(split(as.data.frame(x)[-1], x$id), c), y)
#&gt; [1] TRUE
英文:

You could do

lapply(split(as.data.frame(x)[-1], x$id), c)
#&gt; $a
#&gt; $a$value
#&gt; [1] 1
#&gt; 
#&gt; $a$othervalue
#&gt; [1] 3
#&gt; 
#&gt; 
#&gt; $b
#&gt; $b$value
#&gt; [1] 2
#&gt; 
#&gt; $b$othervalue
#&gt; [1] 4

Which is identical to y:

identical(lapply(split(as.data.frame(x)[-1], x$id), c), y)
#&gt; [1] TRUE

答案3

得分: 4

Since you're mentioning purrr in your tags, you can use purrr::transpose:

purrr::transpose(x[-1], .names = x[[1]])

# $a
# $a$value
# [1] 1
# 
# $a$othervalue
# [1] 3
# 
# 
# $b
# $b$value
# [1] 2
# 
# $b$othervalue
# [1] 4

Your second question looks like recursive splitting. To do so, a convenient option is collapse::rsplit:

collapse::rsplit(data.frame(x), ~ id + key)

# $a
# $a$bar
# [1] 3
# 
# $a$foo
# [1] 1
# 
# 
# $b
# $b$foo
# [1] 2
英文:

Since you're mentioning purrr in your tags, you can use purrr::transpose:

purrr::transpose(x[-1], .names = x[[1]])

# $a
# $a$value
# [1] 1
# 
# $a$othervalue
# [1] 3
# 
# 
# $b
# $b$value
# [1] 2
# 
# $b$othervalue
# [1] 4

Your second question looks like recursive splitting. To do so, a convenient option is collapse::rsplit:

collapse::rsplit(data.frame(x), ~ id + key)

# $a
# $a$bar
# [1] 3
# 
# $a$foo
# [1] 1
# 
# 
# $b
# $b$foo
# [1] 2

答案4

得分: 3

以下是您提供的代码的中文翻译:

保持简单:

foo <- function(x) {
  n <- length(x$id)
  y <- vector(mode = "list", length = n) | setNames(x$id)
  for (i in seq_len(n)) y[[i]] <- list(value = x$value[i], othervalue = x$othervalue[i])
  y
}

性能测试(使用稍大的数据):

x <- list(id = c(letters, LETTERS),
          value = 1:52,
          othervalue = (1:52 + 100)
    )
bench::mark(purr = purrr::transpose(x[-1], .names = x[[1]]),
            Map = setNames(do.call(Map, c(list, x[-1])), x[[1]]),
            loop = foo(x)) 

#   表达式          最小时间   中位时间 itr/秒    内存分配 gc/秒 n_itr  n_gc 总时间                  
#   <bch:expr>     <bch:tm>   <bch:tm> <dbl>   <bch:byt> <dbl> <int> <dbl> <bch:tm>            
# 1 purr           5µs        5.8µs   137969. 1.2KB     27.6  9998     2 72.5ms
# 2 Map            32.3µs     34.7µs  27567.  464B     13.8  9995     5 362.6ms
# 3 loop           16.5µs     17.5µs  52962.  464B     15.9  9997     3 188.8ms 

请注意,我已经忽略了代码部分,并只提供了翻译好的内容。如果您有其他需要,请随时告诉我。

英文:

Keeping it simple:

foo &lt;- function(x) {
  n &lt;- length(x$id)
  y &lt;- vector(mode = &quot;list&quot;, length = n) |&gt; setNames(x$id)
  for (i in seq_len(n)) y[[i]] &lt;- list(value = x$value[i], othervalue = x$othervalue[i])
  y
}

Benchmark (with slightly bigger data):

x &lt;- list(id = c(letters, LETTERS),
          value = 1:52,
          othervalue = (1:52 + 100)
    )
bench::mark(purr = purrr::transpose(x[-1], .names = x[[1]]),
            Map = setNames(do.call(Map, c(list, x[-1])), x[[1]]),
            loop = foo(x)) 

#   expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time                 
#   &lt;bch:expr&gt; &lt;bch:tm&gt; &lt;bch:tm&gt;     &lt;dbl&gt; &lt;bch:byt&gt;    &lt;dbl&gt; &lt;int&gt; &lt;dbl&gt;   &lt;bch:tm&gt;            
# 1 purr            5&#181;s    5.8&#181;s   137969.     1.2KB     27.6  9998     2     72.5ms
# 2 Map          32.3&#181;s   34.7&#181;s    27567.      464B     13.8  9995     5    362.6ms
# 3 loop         16.5&#181;s   17.5&#181;s    52962.      464B     15.9  9997     3    188.8ms 

答案5

得分: 2

更新

关于问题中的更新,您可以尝试使用 split + lapply

lapply(split(list2DF(x[-1]), x[[1]]), \(v) with(v, split(value, key)))

或者我们可以使用 aggregate + Map

with(
    aggregate(x[-1], x[1], as.list),
    setNames(Map(setNames, value, key), id)
)

这将得到以下结果:

$a
$a$bar
[1] 3

$a$foo
[1] 1


$b
$b$foo
[1] 2

对于先前的问题

您可以尝试以下方法:

list2DF(x[-1]) %&gt;%
    split(1:nrow(.)) %&gt;%
    setNames(x[[1]]) %&gt;%
    lapply(c)

这将得到以下结果:

$a
$a$value
[1] 1

$a$othervalue
[1] 3


$b
$b$value
[1] 2

$b$othervalue
[1] 4
英文:

Update

Regarding the update in the question, you can try split + lapply

lapply(split(list2DF(x[-1]), x[[1]]), \(v) with(v, split(value, key)))

or we can use aggregate + Map

with(
    aggregate(x[-1], x[1], as.list),
    setNames(Map(setNames, value, key), id)
)

which gives

$a
$a$bar
[1] 3

$a$foo
[1] 1


$b
$b$foo
[1] 2

For Previous Question

You can try

list2DF(x[-1]) %&gt;%
    split(1:nrow(.)) %&gt;%
    setNames(x[[1]]) %&gt;%
    lapply(c)

which gives

$a
$a$value
[1] 1

$a$othervalue
[1] 3


$b
$b$value
[1] 2

$b$othervalue
[1] 4

huangapple
  • 本文由 发表于 2023年6月12日 18:35:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76455797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定