Open main menu
Home
Random
Recent changes
Special pages
Community portal
Preferences
About Wikipedia
Disclaimers
Incubator escapee wiki
Search
User menu
Talk
Dark mode
Contributions
Create account
Log in
Editing
List comprehension
(section)
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
==Similar constructs== ===Monad comprehension=== In Haskell, a [[monads in functional programming#do-notation|monad comprehension]] is a generalization of the list comprehension to other [[monads in functional programming]]. ===Set comprehension=== The [[Python (programming language)|Python]] language introduces syntax for [[set (computer science)|set]] comprehensions starting in version 2.7. Similar in form to list comprehensions, set comprehensions generate Python sets instead of lists. <syntaxhighlight lang="pycon"> >>> s = {v for v in 'ABCDABCD' if v not in 'CB'} >>> print(s) {'A', 'D'} >>> type(s) <class 'set'> >>> </syntaxhighlight> [[Racket (programming language)|Racket]] set comprehensions generate Racket sets instead of lists. <syntaxhighlight lang="scheme"> (for/set ([v "ABCDABCD"] #:unless (member v (string->list "CB"))) v)) </syntaxhighlight> ===Dictionary comprehension=== The [[Python (programming language)|Python]] language introduced a new syntax for [[associative array|dictionary]] comprehensions in version 2.7, similar in form to list comprehensions but which generate Python [https://docs.python.org/library/stdtypes.html#dict dicts] instead of lists. <syntaxhighlight lang="pycon"> >>> s = {key: val for key, val in enumerate('ABCD') if val not in 'CB'} >>> s {0: 'A', 3: 'D'} >>> </syntaxhighlight> Racket hash table comprehensions generate Racket hash tables (one implementation of the Racket dictionary type). <syntaxhighlight lang="scheme"> (for/hash ([(val key) (in-indexed "ABCD")] #:unless (member val (string->list "CB"))) (values key val)) </syntaxhighlight> ===Parallel list comprehension=== The [[Glasgow Haskell Compiler]] has an extension called '''parallel list comprehension''' (also known as '''zip-comprehension''') that permits multiple independent branches of qualifiers within the list comprehension syntax. Whereas qualifiers separated by commas are dependent ("nested"), qualifier branches separated by pipes are evaluated in parallel (this does not refer to any form of multithreadedness: it merely means that the branches are [[Map (higher-order function)|zipped]]). <syntaxhighlight lang="haskell"> -- regular list comprehension a = [(x,y) | x <- [1..5], y <- [3..5]] -- [(1,3),(1,4),(1,5),(2,3),(2,4) ... -- zipped list comprehension b = [(x,y) | (x,y) <- zip [1..5] [3..5]] -- [(1,3),(2,4),(3,5)] -- parallel list comprehension c = [(x,y) | x <- [1..5] | y <- [3..5]] -- [(1,3),(2,4),(3,5)] </syntaxhighlight> Racket's comprehensions standard library contains parallel and nested versions of its comprehensions, distinguished by "for" vs "for*" in the name. For example, the vector comprehensions "for/vector" and "for*/vector" create vectors by parallel versus nested iteration over sequences. The following is Racket code for the Haskell list comprehension examples. <syntaxhighlight lang="scheme"> > (for*/list ([x (in-range 1 6)] [y (in-range 3 6)]) (list x y)) '((1 3) (1 4) (1 5) (2 3) (2 4) (2 5) (3 3) (3 4) (3 5) (4 3) (4 4) (4 5) (5 3) (5 4) (5 5)) > (for/list ([x (in-range 1 6)] [y (in-range 3 6)]) (list x y)) '((1 3) (2 4) (3 5)) </syntaxhighlight> In Python, we could do as follows: <syntaxhighlight lang="pycon"> >>> # regular list comprehension >>> a = [(x, y) for x in range(1, 6) for y in range(3, 6)] [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), ... >>> >>> # parallel/zipped list comprehension >>> b = [x for x in zip(range(1, 6), range(3, 6))] [(1, 3), (2, 4), (3, 5)] </syntaxhighlight> In Julia, practically the same results can be achieved as follows: <syntaxhighlight lang="julia"> # regular array comprehension >>> a = [(x, y) for x in 1:5 for y in 3:5] # parallel/zipped array comprehension >>> b = [x for x in zip(1:3, 3:5)] </syntaxhighlight> with the only difference that instead of lists, in Julia, we have arrays. === XQuery and XPath === Like the original NPL use, these are fundamentally database access languages. This makes the comprehension concept more important, because it is computationally infeasible to retrieve the entire list and operate on it (the initial 'entire list' may be an entire XML database). In XPath, the expression: <syntaxhighlight lang="xquery"> /library/book//paragraph[@style='first-in-chapter'] </syntaxhighlight> is conceptually evaluated as a series of "steps" where each step produces a list and the next step applies a filter function to each element in the previous step's output.<ref>{{cite web | url = http://www.w3.org/TR/xpath#section-Location-Steps | title = 2.1 Location Steps | work = XML Path Language (XPath) | date = 16 November 1999 | publisher = [[W3C]] | access-date = 24 December 2008 | archive-url = https://web.archive.org/web/20121209085946/http://www.w3.org/TR/xpath/#section-Location-Steps | archive-date = 9 December 2012 | url-status = dead }}</ref> In XQuery, full XPath is available, but [[FLWOR]] statements are also used, which is a more powerful comprehension construct.<ref>{{cite web | url = https://www.w3schools.com/XQuery/xquery_flwor.asp | title = XQuery FLWOR Expressions | work = [[W3Schools]] | url-status = dead | archive-url = https://web.archive.org/web/20111008001258/http://w3schools.com/xquery/xquery_flwor.asp | archive-date = 2011-10-08 }}</ref> <syntaxhighlight lang="xquery"> for $b in //book where $b[@pages < 400] order by $b//title return <shortBook> <title>{$b//title}</title> <firstPara>{($book//paragraph)[1]}</firstPara> </shortBook> </syntaxhighlight> Here the XPath //book is evaluated to create a sequence (aka list); the where clause is a functional "filter", the order by sorts the result, and the {{tag|shortBook}} XML snippet is actually an [[anonymous function]] that builds/transforms XML for each element in the sequence using the 'map' approach found in other functional languages. So, in another functional language the above FLWOR statement may be implemented like this: <syntaxhighlight lang="xquery"> map( newXML(shortBook, newXML(title, $1.title), newXML(firstPara, $1...)) filter( lt($1.pages, 400), xpath(//book) ) ) </syntaxhighlight> === LINQ in C# === [[C Sharp (programming language)|C#]] 3.0 has a group of related features called [[Language Integrated Query|LINQ]], which defines a set of query operators for manipulating object enumerations. <syntaxhighlight lang="csharp"> var s = Enumerable.Range(0, 100).Where(x => x * x > 3).Select(x => x * 2); </syntaxhighlight> It also offers an alternative comprehension syntax, reminiscent of SQL: <syntaxhighlight lang="csharp"> var s = from x in Enumerable.Range(0, 100) where x * x > 3 select x * 2; </syntaxhighlight> LINQ provides a capability over typical list comprehension implementations. When the root object of the comprehension implements the <code>IQueryable</code> interface, rather than just executing the chained methods of the comprehension, the entire sequence of commands are converted into an [[abstract syntax tree]] (AST) object, which is passed to the IQueryable object to interpret and execute. This allows, amongst other things, for the IQueryable to * rewrite an incompatible or inefficient comprehension * translate the AST into another query language (e.g. SQL) for execution === C++ === C++ does not have any language features directly supporting list comprehensions but [[operator overloading]] (e.g., overloading <code>|</code>, <code>>></code>, <code>>>=</code>) has been used successfully to provide expressive syntax for "embedded" query [[domain-specific language]]s (DSL). Alternatively, list comprehensions can be constructed using the [[erase-remove idiom]] to select elements in a container and the STL algorithm for_each to transform them. <syntaxhighlight lang="cpp"> #include <algorithm> #include <list> #include <numeric> using namespace std; template<class C, class P, class T> C comprehend(C&& source, const P& predicate, const T& transformation) { // initialize destination C d = forward<C>(source); // filter elements d.erase(remove_if(begin(d), end(d), predicate), end(d)); // apply transformation for_each(begin(d), end(d), transformation); return d; } int main() { list<int> range(10); // range is a list of 10 elements, all zero iota(begin(range), end(range), 1); // range now contains 1, 2, ..., 10 list<int> result = comprehend( range, [](int x) { return x * x <= 3; }, [](int &x) { x *= 2; }); // result now contains 4, 6, ..., 20 } </syntaxhighlight> There is some effort in providing C++ with list-comprehension constructs/syntax similar to the set builder notation. * In [[Boost C++ Libraries|Boost]]. Range [http://www.boost.org/libs/range] library there is a notion of adaptors [http://www.boost.org/libs/range/doc/html/range/reference/adaptors.html] that can be applied to any range and do filtering, transformation etc. With this library, the original Haskell example would look like (using Boost.Lambda [http://www.boost.org/libs/lambda] for anonymous filtering and transforming functions) ([http://codepad.org/y4bpgLJu Full example]):<syntaxhighlight lang="cpp"> counting_range(1,10) | filtered( _1*_1 > 3 ) | transformed(ret<int>( _1*2 )) </syntaxhighlight> * This<ref>{{cite web | url = http://mfoliveira.org/blog/2011/01/04/simple-list-comprehension-in-cp-using-preprocessor-macros/ | title = Single-variable List Comprehension in C++ using Preprocessor Macros | access-date = 2011-01-09 | archive-url = https://web.archive.org/web/20110821211656/http://mfoliveira.org/blog/2011/01/04/simple-list-comprehension-in-cp-using-preprocessor-macros/ | archive-date = 2011-08-21 | url-status = usurped }}</ref> implementation uses a macro and overloads the << operator. It evaluates any expression valid inside an 'if', and any variable name may be chosen. It's not [[thread safety|threadsafe]], however. Usage example: <syntaxhighlight lang="cpp"> list<int> N; list<double> S; for (int i = 0; i < 10; i++) N.push_back(i); S << list_comprehension(3.1415 * x, x, N, x * x > 3) </syntaxhighlight> * This<ref>{{cite web | url = http://www.tedunangst.com/listcc.html | title = C++ list comprehensions | access-date = 2011-01-09 | archive-url = https://web.archive.org/web/20170707125836/http://www.tedunangst.com/listcc.html | archive-date = 2017-07-07 | url-status = dead }}</ref> implementation provides head/tail slicing using classes and operator overloading, and the | operator for filtering lists (using functions). Usage example: <syntaxhighlight lang="cpp"> bool even(int x) { return x % 2 == 0; } bool x2(int &x) { x *= 2; return true; } list<int> l, t; int x, y; for (int i = 0; i < 10; i++) l.push_back(i); (x, t) = l | x2; (t, y) = t; t = l < 9; t = t < 7 | even | x2; </syntaxhighlight> * Language for Embedded Query and Traversal (LEESA<ref>{{cite web | url = http://www.dre.vanderbilt.edu/LEESA/ | title = Language for Embedded Query and Traversal (LEESA)}}</ref>) is an embedded DSL in C++ that implements X-Path-like queries using operator overloading. The queries are executed on richly typed xml trees obtained using xml-to-c++ binding from an XSD. There is absolutely no string encoding. Even the names of the xml tags are classes and therefore, there is no way for typos. If a LEESA expression forms an incorrect path that does not exist in the data model, the C++ compiler will reject the code.<br>Consider a catalog xml. <syntaxhighlight lang="xml"> <catalog> <book> <title>Hamlet</title> <price>9.99</price> <author> <name>William Shakespeare</name> <country>England</country> </author> </book> <book>...</book> ... </catalog> </syntaxhighlight> LEESA provides <code>>></code> for XPath's / separator. XPath's // separator that "skips" intermediate nodes in the tree is implemented in LEESA using what's known as Strategic Programming. In the example below, catalog_, book_, author_, and name_ are instances of catalog, book, author, and name classes, respectively. <syntaxhighlight lang="cpp"> // Equivalent X-Path: "catalog/book/author/name" std::vector<name> author_names = evaluate(root, catalog_ >> book_ >> author_ >> name_); // Equivalent X-Path: "catalog//name" std::vector<name> author_names = evaluate(root, catalog_ >> DescendantsOf(catalog_, name_)); // Equivalent X-Path: "catalog//author[country=="England"]" std::vector<name> author_names = evaluate(root, catalog_ >> DescendantsOf(catalog_, author_) >> Select(author_, [](const author & a) { return a.country() == "England"; }) >> name_); </syntaxhighlight>
Edit summary
(Briefly describe your changes)
By publishing changes, you agree to the
Terms of Use
, and you irrevocably agree to release your contribution under the
CC BY-SA 4.0 License
and the
GFDL
. You agree that a hyperlink or URL is sufficient attribution under the Creative Commons license.
Cancel
Editing help
(opens in new window)