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. > [[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.