简体   繁体   中英

views::flat for C++ ranges?

Javascript can flatten an array:

const nesting = 2;
const arr = [0,[1,[2,3]]].flat(nesting);
console.log(arr);
//output
[0,1,2,3]

It all makes sense because a Javascript array can hold data of mixed types. Can this be expressed using C++ ranges? Is it possible to nest ranges in this way?

What about if you want to flatten a vector of vectors:

const vector<vector<int> > vv={{0,1},{2,3}};
auto rg = vv | views::flat;

Is there such a function in the pipeline?

It's named ranges::views::join and it flattens a range of ranges into a range. (For flattening more layers, you need to join multiple times.)

To be precise, ranges::views::join is the thing that together with ranges::views::single and ranges::views::transform allows you to treat ranges as the monads they are.

This is however different from JavaScript's .flat(n) , which can flatten array which contains elements which are arrays and not arrays. So JavaScript's .flat has a much looser meaning than views::join , in the sense that it accomplishes what join does, but other things as well, which don't make much sense in functional programming, at least not as regards join .

As noted in a comment, flattening all elements of an array such as the one in the question's JavaScript snippet can have sense. But that is an operation that does not belong to the list monad. Monads can be defined in terms of monadic binding ( >>= Haskell, and, for just the list monad, transform(id) | join in C++ with Range-v3) and a constructor ( return or pure in Haskell, and, for just the list monad, ranges::views::single in C++ with Range-v3). These tools alone don't allow one to flatten a tree in a list (see this for what the tree monad is). That's an operation that can be accomplished via folding.

So the bottom line of the above paragraph is:

  • if you are looking for the behavior that .flat(n) exhibits on "uniformly nested" arrays (invented terminology which I hope is obvious by now), then ranges::views::join is there for you;
  • if you are looking for the behavior it exhibits more in general, then you need to invoke the full power of folding, that in C++ goes by the name of std::for_each / ranges::for_each (I'm assuming you have a way to iterate on the structure, ie your structure has .begin() and .end() memebrs, ie it is a range).
const vector<vector<int> > vv={{0,1},{2,3}};
auto rg = vv | views::join;
//rg={0,1,2,3}

const vector<vector<vector<int> > > vv={
{{0,1},{2,3}},
{{4,5},{6,7}}
};
auto rg = vv | views::join | views::join;
//rg={0,1,2,3,4,5,6,7,8}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM