Jeremiah - neat - that's one step closer, but one small thing I still don't understand:
> data <- list(one = c(1, 1), three = c(3), two = c(2, 2)) > r = Reduce(function(acc, item) { append(acc, setNames(length(item), names(item))) }, data, list()) > str(r) List of 3 $ : int 2 $ : int 1 $ : int 2 I wanted the names to remain, but it seems like the "data" parameter loses its names when consumed by the Reduce()? If I print "item" inside the reducing function, it's not got the names. I'm probably missing some central tenet of R here. As to your comment of this being lapply() implemented by Reduce() - as I understand lapply() (or map() in other functional languages), it's limited to returning a list/vector of the same length as the original. Consider this contrived example: > r = Reduce(function(acc, item) { if (length(item) > 1) {append(acc, setNames(length(item), names(item)))} }, data, list()) > str(r) int 2 > r [1] 2 I don't think you could achieve that with lapply()? Thanks Stefan On 28 July 2016 at 20:19, jeremiah rounds <roundsjerem...@gmail.com> wrote: > Basically using Reduce as an lapply in that example, but I think that was > caused by how people started talking about things in the first place =) But > the point is the accumulator can be anything as far as I can tell. > > On Thu, Jul 28, 2016 at 12:14 PM, jeremiah rounds < > roundsjerem...@gmail.com> wrote: > >> Re: >> "What I'm trying to >> work out is how to have the accumulator in Reduce not be the same type as >> the elements of the vector/list being reduced - ideally it could be an S3 >> instance, list, vector, or data frame." >> >> Pretty sure that is not true. See code that follows. I would never >> solve this task in this way though so no comment on the use of Reduce for >> what you described. (Note the accumulation of "functions" in a list is >> just a demo of possibilities). You could accumulate in an environment too >> and potentially gain a lot of copy efficiency. >> >> >> lookup = list() >> lookup[[as.character(1)]] = function() print("1") >> lookup[[as.character(2)]] = function() print("2") >> lookup[[as.character(3)]] = function() print("3") >> >> data = list(c(1,2), c(1,4), c(3,3), c(2,30)) >> >> >> r = Reduce(function(acc, item) { >> append(acc, list(lookup[[as.character(min(item))]])) >> }, data,list()) >> r >> for(f in r) f() >> >> >> On Thu, Jul 28, 2016 at 5:09 AM, Stefan Kruger <stefan.kru...@gmail.com> >> wrote: >> >>> Ulrik - many thanks for your reply. >>> >>> I'm aware of many simple solutions as the one you suggest, both iterative >>> and functional style - but I'm trying to learn how to bend Reduce() for >>> the >>> purpose of using it in more complex processing tasks. What I'm trying to >>> work out is how to have the accumulator in Reduce not be the same type as >>> the elements of the vector/list being reduced - ideally it could be an S3 >>> instance, list, vector, or data frame. >>> >>> Here's a more realistic example (in Elixir, sorry) >>> >>> Given two lists: >>> >>> 1. data: maps an id string to a vector of revision strings >>> 2. dict: maps known id/revision pairs as a string to true (or 1) >>> >>> find the items in data not already in dict, returned as a named list. >>> >>> ```elixir >>> data = %{ >>> "id1" => ["rev1.1", "rev1.2"], >>> "id2" => ["rev2.1"], >>> "id3" => ["rev3.1", "rev3.2", "rev3.3"] >>> } >>> >>> dict = %{ >>> "id1/rev1.1" => 1, >>> "id1/rev1.2" => 1, >>> "id3/rev3.1" => 1 >>> } >>> >>> # Find the items in data not already in dict. Return as a grouped map >>> >>> Map.keys(data) >>> |> Enum.flat_map(fn id -> Enum.map(data[id], fn rev -> {id, rev} end) >>> end) >>> |> Enum.filter(fn {id, rev} -> !Dict.has_key?(dict, "#{id}/#{rev}") >>> end) >>> |> Enum.reduce(%{}, fn ({k, v}, d) -> Map.update(d, k, [v], &[v|&1]) >>> end) >>> ``` >>> >>> >>> >>> >>> On 28 July 2016 at 12:03, Ulrik Stervbo <ulrik.ster...@gmail.com> wrote: >>> >>> > Hi Stefan, >>> > >>> > in that case,lapply(data, length) should do the trick. >>> > >>> > Best wishes, >>> > Ulrik >>> > >>> > On Thu, 28 Jul 2016 at 12:57 Stefan Kruger <stefan.kru...@gmail.com> >>> > wrote: >>> > >>> >> David - many thanks for your response. >>> >> >>> >> What I tried to do was to turn >>> >> >>> >> data <- list(one = c(1, 1), three = c(3), two = c(2, 2)) >>> >> >>> >> into >>> >> >>> >> result <- list(one = 2, three = 1, two = 2) >>> >> >>> >> that is creating a new list which has the same names as the first, but >>> >> where the values are the vector lengths. >>> >> >>> >> I know there are many other (and better) trivial ways of achieving >>> this - >>> >> my aim is less the task itself, and more figuring out if this can be >>> done >>> >> using Reduce() in the fashion I showed in the other examples I gave. >>> It's >>> >> a >>> >> building block of doing map-filter-reduce type pipelines that I'd >>> like to >>> >> understand how to do in R. >>> >> >>> >> Fumbling in the dark, I tried: >>> >> >>> >> Reduce(function(acc, item) { setNames(c(acc, length(data[item])), >>> item }, >>> >> names(data), accumulate=TRUE) >>> >> >>> >> but setNames sets all the names, not adding one - and acc is still a >>> >> vector, not a list. >>> >> >>> >> It looks like 'lambda.tools.fold()' and possibly 'purrr.reduce()' aim >>> at >>> >> doing what I'd like to do - but I've not been able to figure out quite >>> >> how. >>> >> >>> >> Thanks >>> >> >>> >> Stefan >>> >> >>> >> >>> >> >>> >> On 27 July 2016 at 20:35, David Winsemius <dwinsem...@comcast.net> >>> wrote: >>> >> >>> >> > >>> >> > > On Jul 27, 2016, at 8:20 AM, Stefan Kruger < >>> stefan.kru...@gmail.com> >>> >> > wrote: >>> >> > > >>> >> > > Hi - >>> >> > > >>> >> > > I'm new to R. >>> >> > > >>> >> > > In other functional languages I'm familiar with you can often >>> seed a >>> >> call >>> >> > > to reduce() with a custom accumulator. Here's an example in >>> Elixir: >>> >> > > >>> >> > > map = %{"one" => [1, 1], "three" => [3], "two" => [2, 2]} >>> >> > > map |> Enum.reduce(%{}, fn ({k,v}, acc) -> Map.update(acc, k, >>> >> > > Enum.count(v), nil) end) >>> >> > > # %{"one" => 2, "three" => 1, "two" => 2} >>> >> > > >>> >> > > In R-terms that's reducing a list of vectors to become a new list >>> >> mapping >>> >> > > the names to the vector lengths. >>> >> > > >>> >> > > Even in JavaScript, you can do similar things: >>> >> > > >>> >> > > list = { one: [1, 1], three: [3], two: [2, 2] }; >>> >> > > var result = Object.keys(list).reduceRight(function (acc, item) { >>> >> > > acc[item] = list[item].length; >>> >> > > return acc; >>> >> > > }, {}); >>> >> > > // result == { two: 2, three: 1, one: 2 } >>> >> > > >>> >> > > In R, from what I can gather, Reduce() is restricted such that any >>> >> init >>> >> > > value you feed it is required to be of the same type as the >>> elements >>> >> of >>> >> > the >>> >> > > vector you're reducing -- so I can't build up. So whilst I can >>> do, say >>> >> > > >>> >> > >> Reduce(function(acc, item) { acc + item }, c(1,2,3,4,5), 96) >>> >> > > [1] 111 >>> >> > > >>> >> > > I can't use Reduce to build up a list, vector or data frame? >>> >> > > >>> >> > > What am I missing? >>> >> > > >>> >> > > Many thanks for any pointers, >>> >> > >>> >> > This builds a list: >>> >> > >>> >> > > Reduce(function(acc, item) { c(acc , item) }, c(1,2,3,4,5), 96, >>> >> > accumulate=TRUE) >>> >> > [[1]] >>> >> > [1] 96 >>> >> > >>> >> > [[2]] >>> >> > [1] 96 1 >>> >> > >>> >> > [[3]] >>> >> > [1] 96 1 2 >>> >> > >>> >> > [[4]] >>> >> > [1] 96 1 2 3 >>> >> > >>> >> > [[5]] >>> >> > [1] 96 1 2 3 4 >>> >> > >>> >> > [[6]] >>> >> > [1] 96 1 2 3 4 5 >>> >> > >>> >> > But you are not saying what you want. The other examples were doing >>> >> > something with names but you provided no names for the R example. >>> >> > >>> >> > This would return a list of named vectors: >>> >> > >>> >> > > Reduce(function(acc, item) { setNames( c(acc,item), 1:(item+1)) >>> }, >>> >> > c(1,2,3,4,5), 96, accumulate=TRUE) >>> >> > [[1]] >>> >> > [1] 96 >>> >> > >>> >> > [[2]] >>> >> > 1 2 >>> >> > 96 1 >>> >> > >>> >> > [[3]] >>> >> > 1 2 3 >>> >> > 96 1 2 >>> >> > >>> >> > [[4]] >>> >> > 1 2 3 4 >>> >> > 96 1 2 3 >>> >> > >>> >> > [[5]] >>> >> > 1 2 3 4 5 >>> >> > 96 1 2 3 4 >>> >> > >>> >> > [[6]] >>> >> > 1 2 3 4 5 6 >>> >> > 96 1 2 3 4 5 >>> >> > >>> >> > >>> >> > >>> >> > >>> >> > > Stefan >>> >> > > >>> >> > > >>> >> > > >>> >> > > -- >>> >> > > Stefan Kruger <stefan.kru...@gmail.com> >>> >> > > >>> >> > > [[alternative HTML version deleted]] >>> >> > > >>> >> > > ______________________________________________ >>> >> > > R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see >>> >> > > https://stat.ethz.ch/mailman/listinfo/r-help >>> >> > > PLEASE do read the posting guide >>> >> > http://www.R-project.org/posting-guide.html >>> >> > > and provide commented, minimal, self-contained, reproducible code. >>> >> > >>> >> > David Winsemius >>> >> > Alameda, CA, USA >>> >> > >>> >> > >>> >> >>> >> >>> >> -- >>> >> Stefan Kruger <stefan.kru...@gmail.com> >>> >> >>> >> [[alternative HTML version deleted]] >>> >> >>> >> ______________________________________________ >>> >> R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see >>> >> https://stat.ethz.ch/mailman/listinfo/r-help >>> >> PLEASE do read the posting guide >>> >> http://www.R-project.org/posting-guide.html >>> >> and provide commented, minimal, self-contained, reproducible code. >>> >> >>> > >>> >>> >>> -- >>> Stefan Kruger <stefan.kru...@gmail.com> >>> >>> [[alternative HTML version deleted]] >>> >>> ______________________________________________ >>> R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see >>> https://stat.ethz.ch/mailman/listinfo/r-help >>> PLEASE do read the posting guide >>> http://www.R-project.org/posting-guide.html >>> and provide commented, minimal, self-contained, reproducible code. >>> >> >> > -- Stefan Kruger <stefan.kru...@gmail.com> [[alternative HTML version deleted]] ______________________________________________ R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.