let
in
on
by
8.18
top
← prev up next →

R-LINQ: .NET’s LINQ in RacketπŸ”— i

Turab Jafri <syajafri@iu.edu>
and Paulette Koronkevich <pkoronke@iu.edu>

source code: https://github.com/trajafri/r-linq

(require r-linq ) package: r-linq

This package provides a simple implementation of .NET’s LINQ in Racket.

1Query SyntaxπŸ”— i

LINQ’s grammar (as described here) is represented in the Racket language as follows:

query-expression =
(from varin src
query-body-clause...
final-query-clause)
query-body-clause = (from varin src)
| (join varin srcon exprcomp-funcexpr)
| (join varin srcon exprcomp-funcexprinto var)
| (letvarexpr)
| (where expr)
| (orderby [exprcomp-func]...+)
| (select exprinto var)
| (group exprby exprinto var)
final-query-clause = (select expr)
| (group exprby expr)

A var is a sequence of characters that can be used as a variable in the Racket language.

A src is an expression that evaluates to a sequence.

A expr is a Racket expression.

A comp-func is a Racket procedure that can compare two values.

2Standard LINQ Query OperatorsπŸ”— i

Following operators can be used in a LINQ query body (a query body must terminate with final query operator). The documentation below is based on the official documentation:

final query operator

( select expr)

In a query expression, the select clause specifies the values that will be produced when the query is executed. The result is based on the evaluation of all the previous clauses and on the expressions in the select clause itself.

Examples:
> (from iin '(123)
(select i))

'(1 2 3)

> (from iin '(123)
(select (+ i3)))

'(4 5 6)

> (from iin (list (λ (x)(+ x3))
(λ (x)(+ x4))
(λ (x)(+ x5)))
(select (i1)))

'(4 5 6)

Since a select operator finalizes a query, it might be helpful to post-process the results of a select clause. To do this, the into form of select can be used:

Examples:
> (from iin '(123)
(select iinto j)
(select j))

'(1 2 3)

> (from iin '(123)
(select (+ i3)into j)
(select (- j3)))

'(1 2 3)

More usage of select can be seen under other query operator’s examples.

final query operator

( group exprby expr)

The group clause returns a sequence of (list X(listofY)) that contain zero or more items that match the key value for the group. For example, you can group a sequence of strings according to the first letter in each string. In this case, the first letter is the key, and is the X type of (list X(listofY)) and the grouped items are of type Y.

Examples:
> (from iin '("hello""there""hi""cow""car""cat""dog""test")
(group iby (substring i01)))

'(("h" ("hello" "hi"))

("t" ("there" "test"))

("c" ("cow" "car" "cat"))

("d" ("dog")))

> (from iin '(123456789)
(group iby (modulo i3)))

'((1 (1 4 7)) (2 (2 5 8)) (0 (3 6 9)))

> (from iin '(123456789)
(group iby (even? i)))

'((#f (1 3 5 7 9)) (#t (2 4 6 8)))

> (from iin '(123456789)
(group (+ i1)by (even? i)))

'((#f (2 4 6 8 10)) (#t (3 5 7 9)))

> (from friendshipin `((TurabPaulette)(TurabJoshua)(PauletteTurab)(LaloTurab)
(DanaJoe)(JoshuaLalo)(JacobNick)(NickLalo)
(SamJoshua)(WillJacob)(BrieDana)(JoeJoshua)(JoeWill))
(group (cadr friendship)by (car friendship)))

'((Turab (Paulette Joshua))

(Paulette (Turab))

(Lalo (Turab))

(Dana (Joe))

(Joshua (Lalo))

(Jacob (Nick))

(Nick (Lalo))

(Sam (Joshua))

(Will (Jacob))

(Brie (Dana))

(Joe (Joshua Will)))

Similar to select , we can post-process the results of a group clause by using an into form:

Examples:
> (from iin '("hello""there""hi""cow""car""cat""dog""test")
(group iby (substring i01)into groups)
(select (cdr groups)into res)
(select (car res)))

'(("hello" "hi") ("there" "test") ("cow" "car" "cat") ("dog"))

> (from iin '(123456789)
(group iby (even? i)into groups)
(select (cadr groups)))

'((1 3 5 7 9) (2 4 6 8))

query operator

( letvarexpr)

In a query expression, it is sometimes useful to store the result of a sub-expression in order to use it in subsequent clauses. You can do this with the let keyword, which creates a new range variable and initializes it with the result of the expression you supply.

Examples:
> (from iin '("hello""there""hi""cow""car""cat""dog""test")
(letk(substring i01))
(group iby k))

'(("h" ("hello" "hi"))

("t" ("there" "test"))

("c" ("cow" "car" "cat"))

("d" ("dog")))

> (from iin '(123)
(letj(+ i1))
(select j))

'(2 3 4)

> (from iin '(123)
(letkadd1 )
(select (ki)))

'(2 3 4)

> (from iin '(123)
(letk(> i1))
(select k))

'(#f #t #t)

> (from iin '(123456789)
(letk(odd? i))
(group iby k))

'((#t (1 3 5 7 9)) (#f (2 4 6 8)))

query operator

( where expr)

The where clause is used in a query expression to specify which elements from the data source will be returned in the query expression. It returns those for which the specified condition is true. A single query expression may contain multiple where clauses.

Examples:
> (from iin '(123)
(where (< i2))
(select i))

'(1)

> (from iin '(123)
(where (> i1))
(select (+ i3)))

'(5 6)

> (from iin (list (λ (x)(+ x3))
(λ (x)(+ x4))
(λ (x)(+ x5)))
(where (>= (i1)5))
(select (i1)))

'(5 6)

More usage of where can be seen under other query operator’s examples.

query operator

( from varin src)

The from clause specifies the following:

  • The data source on which the query or sub-query will be run.

  • A local range variable that represents each element in the source sequence.

After initializing a query, the mentioned form of from can be used anywhere in a query body clause to introduce a new data source. The data source referenced in the from clause must be sequence.

Examples:
> (from iin '(123)
(from jin '(456))
(select (list ij)))

'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))

> (from iin '(123)
(from jin '(456))
(from kin '(111))
(select k))

'(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)

> (from iin (list 123)
(from jin (list 345))
(where (= (+ ij)5))
(select (list ij)))

'((1 4) (2 3))

> (from iin (list 123)
(where (> i1))
(from jin '(456))
(where (> j5))
(select (list ij)))

'((2 6) (3 6))

> (letrec [(!(λ (x)(if (zero? x)
1
(* (!(sub1 x))x))))]
(from iin (list 123)
(letfact(!i))
(from jin '(456))
(where (> j4))
(select (list factj))))

'((1 5) (1 6) (2 5) (2 6) (6 5) (6 6))

query operator

( join varin srcon exprcomp-funcexpr)

The join clause is useful for associating elements from different source sequences that have no direct relationship. For example, a food distributor might have a list of suppliers of a certain product, and a list of buyers. A join clause can be used, for example, to create a list of the suppliers and buyers of that product who are all in the same specified region.

A join clause takes two source sequences as input. The elements in each sequence must contain a property that can be compared using the function passed in the join clause. The expr on the right can not contain any range variable other than the one being introduced. The expr on the left can contain any range variable other than the one being introduced.

Examples:
> (from iin '(123)
(join jin '(456)on 1= 1)
(select (list ij)))

'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))

> (from iin '(123)
(from jin '(456))
(join kin '(111)on i> (+ 1k))
(select (list kj)))

'((1 4) (1 4) (1 4) (1 5) (1 5) (1 5) (1 6) (1 6) (1 6))

> (from fshipin `((TurabPaulette)(TurabJoshua)(PauletteTurab)
(LaloTurab)(DanaJoe)(JoshuaLalo)
(JacobNick)(NickLalo)(SamJoshua)
(WillJacob)(BrieDana)(JoeJoshua)(JoeWill))
(join jin '(TurabPauletteJoshuaLalo)on (car fship)equal? j)
(select (list j(cadr fship))))

'((Turab Paulette) (Turab Joshua) (Paulette Turab) (Lalo Turab) (Joshua Lalo))

> (from personin (list (cons "Peter"(cons 18#t))
(cons "Jack"(cons 12#f))
(cons "Tom"(cons 29#t))
(cons "Pat"(cons 19#t)))
(join comp-ownerin (list (cons "Sam""Mac")
(cons "Tom""Dell")
(cons "Jack""Lenovo")
(cons "Peter""Toshiba")
(cons "Tom""Mac"))on (car person)
(car comp-owner))
(select (list (car person)(cddr person)(cdr comp-owner))))

'(("Peter" #t "Toshiba")

("Jack" #f "Lenovo")

("Tom" #t "Dell")

("Tom" #t "Mac"))

To perform a group-join, you can use the into form of join:

Example:
> (from personin (list (cons "Peter"(cons 18#t))
(cons "Jack"(cons 12#f))
(cons "Tom"(cons 29#t))
(cons "Pat"(cons 19#t)))
(join comp-ownerin (list (cons "Sam""Mac")
(cons "Tom""Dell")
(cons "Jack""Lenovo")
(cons "Peter""Toshiba")
(cons "Tom""Mac"))on (car person)
(car comp-owner)into groups)
(select (list (car person)(cddr person)(map cdr groups))))

'(("Peter" #t ("Toshiba"))

("Jack" #f ("Lenovo"))

("Tom" #t ("Dell" "Mac"))

("Pat" #t ()))

query operator

( orderby [key-exprcomp-func]...+)

In a query expression, the orderby clause causes the returned sequence to be sorted. Multiple keys can be specified in order to perform one or more secondary sort operations. The sorting is performed by the function associated to each expr. The function should not contain any range variables introduced in the linq query.

Examples:
> (from iin '(123)
(orderby [i> ])
(select i))

'(3 2 1)

> (from iin '(123)
(from jin '(1212))
(orderby [i> ][j> ])
(select (list ij)))

'((3 2) (3 2) (3 1) (3 1) (2 2) (2 2) (2 1) (2 1) (1 2) (1 2) (1 1) (1 1))

> (from iin '(123)
(from jin '(1212))
(orderby [i> ][j< ])
(select (list ij)))

'((3 1) (3 1) (3 2) (3 2) (2 1) (2 1) (2 2) (2 2) (1 1) (1 1) (1 2) (1 2))

3Query FunctionsπŸ”— i

The operators above are implemented using the following functions that are also provided by r-linq. The documentation below is based on the official documentation:

procedure

( select sel-funcsrc)(listofY)

sel-func:(X->Y)
src:(sequenceofX)
Projects each element of a sequence into a new form.

Examples:
> (select (λ (x)(+ x2))'(123))

'(3 4 5)

> (select add1 4)

'(1 2 3 4)

> (select (λ (x)x)"hello")

'(#\h #\e #\l #\l #\o)

procedure

( select-many sel-funcres-funcsrc)(listofZ)

sel-func:(X->Y)
res-func:(XY->Z)
src:(sequenceofX)
Projects each element of the src sequence and the sequence returned by sel-func and flattens the resulting sequences into one sequence. One can think about this like an abstraction over a nester for loop, where for each X in src, and for each Y in (sel-funcX), a list containing (res-funcXY) is produced.

Examples:
> (select-many (λ (x)'(456))list '(123))

'((1 4) (1 5) (1 6) (2 4) (2 5) (2 6) (3 4) (3 5) (3 6))

'((0 0) (1 0) (1 1) (2 0) (2 1) (2 2))

(λ (xy)(map + xy))'((123)(456)(789)))

'((2 4 6) (8 10 12) (14 16 18))

procedure

( where predsrc)(listofX)

pred:(X->boolean)
src:(sequenceofX)
Filters a sequence of values based on a predicate.

Examples:
> (where even? '(12345))

'(2 4)

'(#\h #\l #\l)

> (where (λ (x)(> (length x)3))'(()(12)(32431)(1324)(1231)))

'((3 2 4 3 1) (1 3 2 4))

procedure

( groupby sel-funcpart-by-funcsrc)

(listof(list Z(listofY)))
sel-func:(X->Y)
part-by-func:(X->Z)
src:(sequenceofX)
Groups the elements of a sequence. The grouping is done based on the part-by-func function, and the sel-func is applied to each grouped item.

Examples:
> (groupby (λ (x)x)(λ (x)(modulo x3))'(123456))

'((1 (1 4)) (2 (2 5)) (0 (3 6)))

> (groupby add1 even? '(123456))

'((#f (2 4 6)) (#t (3 5 7)))

procedure

( join outer-sel-func
inner-sel-func
sel-when
sel-func
outer-src
inner-src)(listofZ)
outer-sel-func:(A->X)
inner-sel-func:(B->Y)
sel-when:(XY->boolean)
sel-func:(AB->Z)
outer-src:(sequenceofA)
inner-src:(sequenceofB)
Correlates the elements of two sequences based on matching keys. The join is based on the sel-when function (with outer-sel-func and inner-sel-func applied), and the resulting list contains results of sel-func function.

Examples:
> (join (λ (x)x)(λ (x)x)
(λ (xy)(= 0(modulo xy)))list
'(12345)'(12345))

'((1 1) (2 1) (2 2) (3 1) (3 3) (4 1) (4 2) (4 4) (5 1) (5 5))

> (join (λ (x)x)(λ (x)x)
(λ (xy)(cons xy))
"helo""helo")

'((#\h . #\h) (#\e . #\e) (#\l . #\l) (#\o . #\o))

procedure

( group-join outer-sel-func
inner-sel-func
sel-when
sel-func
outer-src
inner-src)(listofZ)
outer-sel-func:(A->X)
inner-sel-func:(B->Y)
sel-when:(XY->boolean)
sel-func:(A(listofB)->Z)
outer-src:(sequenceofA)
inner-src:(sequenceofB)
Correlates the elements of two sequences based on key equality, and groups the results. Similar to join, but groups all matched items in inner-src in a list.

Example:
> (group-join (λ (x)x)(λ (x)x)
(λ (xy)(= 0(modulo xy)))
(λ (xy)(list xy))
'(12345)'(12345))

'((1 (1)) (2 (1 2)) (3 (1 3)) (4 (1 2 4)) (5 (1 5)))

procedure

( orderby srcsort-seq)(listofX)

src:(sequenceofX)
sort-seq:(nelistof[XX->boolean])
Sorts the elements of a sequence with the comparator functions. When provided more than one function, the function is first sorted by the first function, then items that were in the same ordering by the second function, and so on...

Examples:
> (orderby '((1. 2)(2. 3)(3. 3)(1. 1)(2. 2))
(list (λ (xy)(> (cdr x)(cdr y)))
(λ (xy)(< (car x)(car y)))))

'((2 . 3) (3 . 3) (1 . 2) (2 . 2) (1 . 1))

> (orderby '((1. 2)(2. 3)(3. 3)(1. 1)(2. 2))
(list (λ (xy)(> (car x)(car y)))
(λ (xy)(< (cdr x)(cdr y)))))

'((3 . 3) (2 . 2) (2 . 3) (1 . 1) (1 . 2))

4LiteralsπŸ”— i

These are the literals used in linq query operators.

syntax

in

Literal used in a from clause.

syntax

on

Literal used in a join clause.

syntax

into

Literal used in a join or continuation clause.

syntax

by

Literal used in a group clause.

top
← prev up next →

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /