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 <dwinsemius at comcast.net> wrote:> > > On Jul 27, 2016, at 8:20 AM, Stefan Kruger <stefan.kruger at 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.kruger at gmail.com> > > > > [[alternative HTML version deleted]] > > > > ______________________________________________ > > R-help at 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.kruger at gmail.com> [[alternative HTML version deleted]]
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.kruger at 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 <dwinsemius at comcast.net> wrote: > > > > > > On Jul 27, 2016, at 8:20 AM, Stefan Kruger <stefan.kruger at 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.kruger at gmail.com> > > > > > > [[alternative HTML version deleted]] > > > > > > ______________________________________________ > > > R-help at 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.kruger at gmail.com> > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at 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]]
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.stervbo at 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.kruger at 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 <dwinsemius at comcast.net> wrote: >> >> > >> > > On Jul 27, 2016, at 8:20 AM, Stefan Kruger <stefan.kruger at 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.kruger at gmail.com> >> > > >> > > [[alternative HTML version deleted]] >> > > >> > > ______________________________________________ >> > > R-help at 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.kruger at gmail.com> >> >> [[alternative HTML version deleted]] >> >> ______________________________________________ >> R-help at 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.kruger at gmail.com> [[alternative HTML version deleted]]
I am not as familiar with those other languages as I should be, but in both examples aren't you using 'map' to call 'reduce' on each component of a list? In R the basic mapping function is lapply. > data <- list(one = c(1, 1), three = c(3), two = c(2, 2)) > rData <- lapply(X=data, FUN=function(dataElement)Reduce(f=function(acc,item)acc+1L, x=dataElement, init=0L)) > str(rData) List of 3 $ one : int 2 $ three: int 1 $ two : int 2 Bill Dunlap TIBCO Software wdunlap tibco.com On Thu, Jul 28, 2016 at 3:55 AM, Stefan Kruger <stefan.kruger at 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 <dwinsemius at comcast.net> wrote: > > > > > > On Jul 27, 2016, at 8:20 AM, Stefan Kruger <stefan.kruger at 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.kruger at gmail.com> > > > > > > [[alternative HTML version deleted]] > > > > > > ______________________________________________ > > > R-help at 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.kruger at gmail.com> > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at 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]]