linq to objects 101 samples c to aplwin

69
101 LINQ to Objects Samples: From C# to APL+Win Ajay Askoolum © Ajay Askoolum Language Integrated Query (LINQ) is an extension to C#, available from version 3.0 1 , that is, with Visual Studio 2008; LINQ is a standard for querying and updating data. The syntax of LINQ integrates with that of the host language, C# or Visual Basic.Net. Here, I am interested in LINQ to Objects—the other implementations are LINQ to SQL, LINQ to Entities, LINQ to DataSet, and LINQ to XML—that deals with in-memory data or, more generally, collections. APL+Win, A Programming Language (APL) has been about language integrated data manipulation— arrays, vectors, and nested or jagged arrays—throughout its history 2 . Here I am interested in LINQ to Objects as a formal deliverable from APL+Win. With its strong/unique integration of Component Object Model (COM) technology into its language features, APL+Win delivers LINQ functionality either in conjunction with C# as a COM Server or on a standalone basis. In this article, I present LINQ to Objects implemented in C# and APL+Win side by side. Above all, LINQ provides a platform for extolling the capabilities of APL+Win using the same vocabulary as a C# developer! The small price of this opportunity is the acquisition of a grasp of the LINQ to Objects concepts. I urge you to read the ‘Partitioning Operators’ section even if LINQ to Objects is not within your sphere of interest right now. For APL+Win users, this group of operators will be very familiar. That C# is now incorporating these features into the language does indeed suggest that APL+Win is a language that is ahead of time. Table of Contents Table of Contents ........................................................................................................................ 1 1.1 The Agenda ...................................................................................................................... 5 1.1.1 The terms of reference............................................................................................................... 6 1.1.2 The payoff for general APL+Win programming ......................................................................... 6 1.1.2.1 Replicating the experience................................................................................................................... 7 1.1.3 APL+Win and Dot Net Accessibility ........................................................................................... 8 1.1.4 Why LINQ to Objects? ............................................................................................................... 9 1.2 Getting Started.................................................................................................................. 9 1.2.1 Understanding the code ............................................................................................................. 9 1.2.1.1 Language symbols ............................................................................................................................. 10 1.2.1.2 What is the question?......................................................................................................................... 11 1.3 Restriction Operators ...................................................................................................... 11 1.3.1 Where - Simple 1 ..................................................................................................................... 11 1.3.1.1 C# code .............................................................................................................................................. 11 1.3.1.2 APL+Win code .................................................................................................................................. 12 1.3.1.3 Understanding the standard result ..................................................................................................... 12 1.3.1.4 Method Signature .............................................................................................................................. 13 1.3.1.5 Further tests ....................................................................................................................................... 14 1.3.2 Where - Simple 2 ..................................................................................................................... 14 1.3.3 Where - Simple 3 ..................................................................................................................... 16 1 Dot Net Framework 3.5. 2 Unfortunately, LINQ and APL+Win use different jargon to describe identical concepts; I expect that the LINQ vocabulary will prevail.

Upload: dang-duy-tran

Post on 10-Oct-2014

75 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Linq to Objects 101 Samples C to AplWin

101 LINQ to Objects Samples: From C# to APL+Win

Ajay Askoolum

© Ajay Askoolum

Language Integrated Query (LINQ) is an extension to C#, available from version 3.0

1, that is, with Visual

Studio 2008; LINQ is a standard for querying and updating data. The syntax of LINQ integrates with that of the host language, C# or Visual Basic.Net. Here, I am interested in LINQ to Objects—the other implementations are LINQ to SQL, LINQ to Entities, LINQ to DataSet, and LINQ to XML—that deals with in-memory data or, more generally, collections.

APL+Win, A Programming Language (APL) has been about language integrated data manipulation—

arrays, vectors, and nested or jagged arrays—throughout its history2. Here I am interested in LINQ to Objects

as a formal deliverable from APL+Win. With its strong/unique integration of Component Object Model (COM) technology into its language features, APL+Win delivers LINQ functionality either in conjunction with C# as a COM Server or on a standalone basis.

In this article, I present LINQ to Objects implemented in C# and APL+Win side by side. Above all, LINQ

provides a platform for extolling the capabilities of APL+Win using the same vocabulary as a C# developer! The small price of this opportunity is the acquisition of a grasp of the LINQ to Objects concepts.

I urge you to read the ‘Partitioning Operators’ section even if LINQ to Objects is not within your sphere of

interest right now. For APL+Win users, this group of operators will be very familiar. That C# is now incorporating these features into the language does indeed suggest that APL+Win is a language that is ahead of time.

Table of Contents

Table of Contents ........................................................................................................................ 1 1.1 The Agenda ...................................................................................................................... 5

1.1.1 The terms of reference...............................................................................................................6 1.1.2 The payoff for general APL+Win programming .........................................................................6

1.1.2.1 Replicating the experience...................................................................................................................7 1.1.3 APL+Win and Dot Net Accessibility ...........................................................................................8 1.1.4 Why LINQ to Objects? ...............................................................................................................9

1.2 Getting Started.................................................................................................................. 9 1.2.1 Understanding the code.............................................................................................................9

1.2.1.1 Language symbols .............................................................................................................................10 1.2.1.2 What is the question?.........................................................................................................................11

1.3 Restriction Operators...................................................................................................... 11 1.3.1 Where - Simple 1 .....................................................................................................................11

1.3.1.1 C# code ..............................................................................................................................................11 1.3.1.2 APL+Win code..................................................................................................................................12 1.3.1.3 Understanding the standard result .....................................................................................................12 1.3.1.4 Method Signature ..............................................................................................................................13 1.3.1.5 Further tests .......................................................................................................................................14

1.3.2 Where - Simple 2 .....................................................................................................................14 1.3.3 Where - Simple 3 .....................................................................................................................16

1 Dot Net Framework 3.5. 2 Unfortunately, LINQ and APL+Win use different jargon to describe identical concepts; I expect that the LINQ vocabulary will prevail.

Page 2: Linq to Objects 101 Samples C to AplWin

Page 2 of 69

1.3.4 Where - Drilldown ....................................................................................................................17 1.3.5 Where - Indexed ......................................................................................................................18

1.4 Projection Operators....................................................................................................... 19 1.4.1 Select - Simple 1......................................................................................................................19

1.4.1.1 Linq6 in focus....................................................................................................................................19 1.4.2 Select - Simple 2......................................................................................................................20 1.4.3 Select - Transformation............................................................................................................20 1.4.4 Select - Anonymous Types 1 ...................................................................................................21 1.4.5 Select - Anonymous Types 2 ...................................................................................................21 1.4.6 Select - Anonymous Types 3 ...................................................................................................22 1.4.7 Select - Indexed .......................................................................................................................22 1.4.8 Select - Filtered........................................................................................................................23 1.4.9 SelectMany - Compound from 1 ..............................................................................................23 1.4.10 SelectMany - Compound from 2 ............................................................................................24 1.4.11 SelectMany - Compound from 3 ............................................................................................24 1.4.12 SelectMany - from Assignment ..............................................................................................25 1.4.13 SelectMany - Multiple from ....................................................................................................26 1.4.14 SelectMany - Indexed ............................................................................................................27

1.5 Partitioning Operators..................................................................................................... 28 1.5.1 Take - Simple...........................................................................................................................28 1.5.2 Take - Nested ..........................................................................................................................28

1.5.2.1 First two customers in Washington and all their orders ....................................................................29 1.5.2.2 First 3 customers in Washington and their first 5 orders...................................................................29

1.5.3 Skip - Simple............................................................................................................................29 1.5.4 Skip - Nested ...........................................................................................................................29 1.5.5 TakeWhile - Simple..................................................................................................................30 1.5.6 TakeWhile - Indexed ................................................................................................................30 1.5.7 SkipWhile - Simple...................................................................................................................31 1.5.8 SkipWhile - Indexed .................................................................................................................31

1.6 Ordering Operators......................................................................................................... 31 1.6.1 OrderBy - Simple 1 ..................................................................................................................31 1.6.2 OrderBy - Simple 2 ..................................................................................................................32 1.6.3 OrderBy - Simple 3 ..................................................................................................................32

1.6.3.1 Where is the difference? ....................................................................................................................32 1.6.4 OrderBy - Comparer ................................................................................................................33 1.6.5 OrderByDescending - Simple 1 ...............................................................................................33 1.6.6 OrderByDescending - Simple 2 ...............................................................................................33 1.6.7 OrderByDescending - Comparer .............................................................................................34 1.6.8 ThenBy - Simple ......................................................................................................................34 1.6.9 ThenBy - Comparer .................................................................................................................35 1.6.10 ThenByDescending - Simple .................................................................................................35 1.6.11 ThenByDescending - Comparer ............................................................................................35 1.6.12 Reverse..................................................................................................................................36

1.7 Grouping Operators ........................................................................................................ 36 1.7.1 GroupBy - Simple 1..................................................................................................................36 1.7.2 GroupBy - Simple 2..................................................................................................................37 1.7.3 GroupBy - Simple 3..................................................................................................................37 1.7.4 GroupBy - Nested ....................................................................................................................38 1.7.5 GroupBy – Comparer...............................................................................................................38 1.7.6 GroupBy – Comparer, Mapped................................................................................................38

1.8 Set Operators ................................................................................................................. 39 1.8.1 Distinct - 1 ................................................................................................................................39 1.8.2 Distinct - 2 ................................................................................................................................39 1.8.3 Union - 1 ..................................................................................................................................40 1.8.4 Union - 2 ..................................................................................................................................40 1.8.5 Intersect - 1 ..............................................................................................................................41 1.8.6 Intersect - 2 ..............................................................................................................................41 1.8.7 Except - 1.................................................................................................................................42 1.8.8 Except - 2.................................................................................................................................42

Page 3: Linq to Objects 101 Samples C to AplWin

Page 3 of 69

1.9 Conversion Operators..................................................................................................... 43 1.9.1 To Array ...................................................................................................................................43 1.9.2 To List ......................................................................................................................................43 1.9.3 To Dictionary............................................................................................................................43 1.9.4 OfType .....................................................................................................................................44

1.10 Element Operators........................................................................................................ 44 1.10.1 First - Simple..........................................................................................................................44 1.10.2 First – Condition (missing at URL) .........................................................................................45 1.10.3 First - Indexed ........................................................................................................................45 1.10.4 FirstOrDefault - Simple ..........................................................................................................45 1.10.5 FirstOrDefault - Condition ......................................................................................................46 1.10.6 FirstOrDefault - Indexed.........................................................................................................46 1.10.7 ElementAt ..............................................................................................................................47

1.11 Generation Operators ................................................................................................... 48 1.11.1 Range ....................................................................................................................................48 1.11.2 Repeat ...................................................................................................................................48

1.12 Quantifiers .................................................................................................................... 49 1.12.1 Any - Simple...........................................................................................................................49 1.12.2 Any - Indexed.........................................................................................................................49 1.12.3 Any - Grouped........................................................................................................................49 1.12.4 All - Simple.............................................................................................................................49 1.12.5 All - Indexed ...........................................................................................................................50 1.12.6 All - Grouped..........................................................................................................................50

1.13 Aggregate Operators .................................................................................................... 50 1.13.1 Count - Simple .......................................................................................................................50 1.13.2 Count - Conditional ................................................................................................................51 1.13.3 Count - Indexed .....................................................................................................................51 1.13.4 Count - Nested.......................................................................................................................52 1.13.5 Count - Grouped ....................................................................................................................52 1.13.6 Sum - Simple .........................................................................................................................52 1.13.7 Sum - Projection ....................................................................................................................53 1.13.8 Sum - Grouped ......................................................................................................................53 1.13.9 Min - Simple ...........................................................................................................................53 1.13.10 Min - Projection ....................................................................................................................54 1.13.11 Min - Grouped ......................................................................................................................54 1.13.12 Min - Elements .....................................................................................................................54 1.13.13 Max - Simple ........................................................................................................................55 1.13.14 Max - Projection ...................................................................................................................55 1.13.15 Max - Grouped .....................................................................................................................55 1.13.16 Max - Elements ....................................................................................................................56 1.13.17 Average - Simple .................................................................................................................56 1.13.18 Average - Projection ............................................................................................................56 1.13.19 Average - Grouped ..............................................................................................................57 1.13.20 Fold - Simple........................................................................................................................57 1.13.21 Fold - Seed ..........................................................................................................................57

1.14 Miscellaneous Operators .............................................................................................. 58 1.14.1 Concat - 1 ..............................................................................................................................58 1.14.2 Concat - 2 ..............................................................................................................................58 1.14.3 EqualAll - 1.............................................................................................................................58 1.14.4 EqualAll - 2.............................................................................................................................59

1.14.4.1 EqualAll - 2 : Extension ..................................................................................................................59 1.15 Custom Sequence Operators ....................................................................................... 59

1.15.1 Combine.................................................................................................................................60 1.15.1.1 C#:APL+Win comparison ...............................................................................................................60

1.16 Query Execution ........................................................................................................... 61 1.16.1 Deferred .................................................................................................................................61 1.16.2 Immediate ..............................................................................................................................61 1.16.3 Query Reuse..........................................................................................................................62

Page 4: Linq to Objects 101 Samples C to AplWin

Page 4 of 69

1.17 Time for 101 APL+Win samples? ................................................................................. 62 1.17.1 Some eligible topics ...............................................................................................................62

1.17.1.1 Example 1 - Return the sign of all elements of a numeric vector/array ..........................................62 1.17.1.2 Example 2 - Return the magnitude indicator of all elements of a numeric vector/array.................62 1.17.1.3 Example 3 – Apply the percentage of increase ...............................................................................62 1.17.1.4 Example 4 – Re-calculate the diagonal elements of a numeric array..............................................63 1.17.1.5 Example 5 – Return the powers of 2 of each element of a numeric vector/array............................63

References................................................................................................................................. 63

Appendix A – Product & Customer Lists ................................................................................ 65

Index........................................................................................................................................... 67

Code Listings............................................................................................................................. 69

Page 5: Linq to Objects 101 Samples C to AplWin

101 LINQ to Objects Samples: From C# to APL+Win

Ajay Askoolum

© Ajay Askoolum

1.1 The Agenda

The agenda is set at the following Universal Resource Locator (URL):

http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx

• Alas, the material at his URL does not refer to APL+Win at all, as to be expected!

Page 6: Linq to Objects 101 Samples C to AplWin

Page 6 of 69

• A much more serious criticism is that the URL does not provide complete code samples. A number of the code snippets do not lend themselves to simple copy & paste into another project; some of the sample codes are also ‘incorrect’

3. Although the basic code listings are useful, the supporting code

dependencies are missing4.

• The code samples simply demonstrate concepts5: the results of sample queries (written to the

console) shown at the URL provide valuable insight into the functionality, especially from the point of view of replicating them in APL+Win.

• If you count the number of samples, there are fewer than the 101 suggested by the title; and a number of them—such as Linq60—do not work. This is not only misleading but also highly unsatisfactory, not least because of the pedigree of its origin—Microsoft—and the fact that this passes for reference material.

In spite of all the shortcomings, this provides an excellent opportunity for exploring a brand new feature of

the contemporary flagship language; ore to the point, this provides the terms of reference for illustrating APL+Win techniques that have been part of the language from the outset. I have included the missing samples in this article.

1.1.1 The terms of reference

The code samples at the URL have the data that they manipulate either hard-coded or drawn from supporting functions. The functions are not parameterised.

My objective is to write a COM server in C# and use it with APL+Win, and to compare the results from C#

with those from APL+Win, in the APL+Win immediate mode. In order to extend the scope of this exercise, some of the methods in C# and APL also accept arguments in client/server mode.

This serves several purposes.

• C# uses complex data types such as the product and customer lists; although these are akin to APL+Win’s nested arrays, there is an important difference. C# refers to the data items by name, something that is not possible in APL+Win. In the APL+Win environment, I refer to the data items by their position or cardinal order in the nested array. Therefore, I also need to coax C# to supply the data in a simpler nested/jagged array format for use by APL+Win.

• A number of refinements in the C# examples are not obvious from the examples given. For example, UNION disregards duplicated elements in its result; appropriate arguments to such functions can highlight such features.

• Overall, this demonstrates C# and APL+Win in a fully functional client/server configuration—an option for any application.

1.1.2 The payoff for general APL+Win programming

LINQ techniques are interesting from point of view of APL+Win for several reasons.

• All data in APL+Win are objects or, for a simplistic view, arrays; LINQ deals with such objects.

3 For example, the code for the class CustomSequenceOperators is incorrect; Linq96 shows wordsA.EqualAll(wordsB) which should be

wordsA.SequenceEqual(wordsB). 4 For example, functions such as GetProductList and GetCustomerList, are missing. 5 The code outputs results to the console: as such, modifications are required to incorporate them in class libraries so that they can take arguments and

return results.

Page 7: Linq to Objects 101 Samples C to AplWin

Page 7 of 69

• Although C# and APL+Win operate in disparate environments, this paper demonstrates how well the two can work together (the prospects for Visual APL which works from the same environment as C# are even better!).

• I have not developed optimised code for my purpose or designed code for re-use. However, there are subtle opportunities to harvest APL+Win idioms. The APL+Win code samples generally use one-dimensional arrays (vectors or nested vectors): they can be generalised for multi-dimensional arrays.

• There is an opportunity to familiarise yourself with another jargon, that of LINQ (and C#): this will be useful for the future in many ways, even if this is not apparent right now.

1.1.2.1 Replicating the experience

I am using APL+Win version 9, with Visual Studio 2008 with Service Pack 1, under Windows XP Professional with Service Pack3.

The APL+Win workspace, LINQ to OBJECTS.W3, is accessible with version 9 of the interpreter. If you have Visual Studio 2008 (any hybrid), one of your options is to attempt to load the project and

recompile it: I have not tested this project with every version of Visual Studio 2008. This will register the COM Dynamic Library (DLL) as required, without further intervention from you.

If you do not have Visual Studio 2008

6, you will need to do the following:

• Download and install Dot Net Framework 3.5

• Register the COM DLL, LINQ.DLL, as follows: ???? Depending on how you use the supplied code, you may receive the following (or similar) error:

ŒWI ERROR: mscorlib exception 80070003 Could not find a part of the path 'C:\AJAY\C#\VS2008\VS2008\LINQ to Objects\LINQ\customers.xml'.

This arises as a result of a hard-coded path reference is DATA.CS. The resolution is to ensure that the

path specified reflects the location of CUSTOMERS.XML in your preferred directory structure7.

The freely downloadable XML NOTEPAD 2007, see below, is a useful tool for creating and examining XML files interactively. You may want to use this tool to examine/audit the results of LINQ queries that use CUSTOMERS.XML.

6 This presents the same scenario as that when deploying your own Dot Net DLL. 7 The project needs re-compilation after any changes to the code.

Page 8: Linq to Objects 101 Samples C to AplWin

Page 8 of 69

1.1.3 APL+Win and Dot Net Accessibility

An often raised complaint, perhaps more often than necessary given the respective infrastructure and lineage of APL+Win and C#, is that APL+Win does not, but should, implement a system function, ŒNET, to enable access to the Dot Net Libraries. I do not subscribe to this view for the following reasons:

• Such an accessibility function will not enhance or optimise the existing legacy of APL+Win applications such that they can benefit from enhancements in the technology that Dot Net heralds. It might be useful for future development: in this context, Visual APL offers better prospects for return on investment since it is closely aligned to APL+Win and is a true Dot Language, not just a Dot NET ‘aware’ one.

• Such a function allows access to the Dot NET foundation class libraries only and not to Dot NET languages such as C#

8. Quite often, it is necessary to write APL Code to glue calls to the foundation

class libraries. This implies that a managed and strongly typed environment (Dot Net) is coerced into an un-managed and loosely typed environment (APL). This has strong implications for application debugging and maintenance. Besides, in such as scenario APL is always playing catch up to improvements in the Dot Net framework.

• APL+Win offers a robust COM interface that enables any user-built DLL to be deployed from within APL+Win. Therefore, the Dot NET environment can be kept separate from the APL+Win environment with several advantages: first, it is not the APL developer who has to code the Dot Net functionality—a Dot Net expert can do it independently of APL—and second, each environment can be debugged separately or together. Play the media file APLWINDEBUGSC#.WMV for an illustration.

8 Remember that LINQ fits within a Dot NET language, such as C# or Visual Basic.NET.

Page 9: Linq to Objects 101 Samples C to AplWin

Page 9 of 69

1.1.4 Why LINQ to Objects?

LINQ to Objects is especially interesting from an APL point of view.

• It is a set of standard operators that eliminates the need for the developer to write loops 1.

• It standardises the means of doing routine tasks relating to data in memory and has a syntax that is very much like that of the host language.

• Is that not what APL+Win is (has always been) about?

1.2 Getting Started

The general format of the illustrations below is to state the purpose of the code sample, list the C# code sample, list the APL+Win function and then to illustrate and discuss the results. The 101 code samples are named Linq1 to Linq101, as seen at the URL; I have retained this convention in coding the APL+Win counterpart functions in order to maintain a 1:1 correspondence.

• For some functions, there is an extension function, named LinqnEx (n designates the numeric sequence of the code sample): I have used this to elaborate on extensions to the functionality in question.

• The source data for the code samples, where required, is internally supplied as complex data types to the C# functions: GetProductList and GetCustomerList are two such examples. I have coded GetProductListEx and GetCustomerListEx which supply the same data as a simple type to APL+Win. Please refer to the end of this document for a complete listing

9 of the C# code—EXPLORE.CS and

DATA.CS—that underlies the COM DLL.

For the sake of clarity as well as completeness, I recommend that you refer to the code sample at the URL and this document concurrently and make appropriate allowance for the errors and omission I have highlighted.

Given that the C# COM DLL, LINQ.DLL, is registered, the following function establishes an instance

thereof; it runs as the latent expression on loading the workspace LINQ to OBJECTS.W3 and should persist for the duration of the session:

’ LINQ [1] © Ajay Askoolum [2] Œwself„'lq' Œwi 'Create' 'LINQ.Explore' ’

The first example, discussed next, is deliberately verbose: this is to familiarise you with the pattern for all the other samples. Therefore, you should study this example first and then may navigate to any other sample, if necessary.

1.2.1 Understanding the code

These pages do not contain a tutorial on either C# or APL+Win: such a task is beyond the scope of this exercise. However, the VS2008 project and the APL+Win workspace contain all the code used herein.

When working through these pages, it may be useful to bear in mind the following:

• Unlike APL+Win which has index origin default to zero, C# always works with index origin set to zero—there is no other option. The APL+Win code I have used here is index-origin independent.

9 I printed the code from Visual Studio 2008 and appended to this PDF.

Page 10: Linq to Objects 101 Samples C to AplWin

Page 10 of 69

• Both APL+Win and C# are case sensitive.

• Both APL+Win and C# use square brackets for indexing; for indexing multi-dimensional arrays, APL+Win uses semi-colon and C# uses comma to separate the co-ordinates.

• The syntax for localisation or scope determination is different in the two languages. With APL+Win, any name included in the header of a function and separated by a semi-colon has the effect of restricting the scope of that name to that function only

10. In C#, any name included within a pair of

opening and closing braces is local.

• In C#, a comma separates elements of an array/vector; the same is true (but optional) for APL+Win numeric elements (although it is more conventional to use spaces) of an array/vector.

• Unlike APL+Win which uses single and double quotes—in pairs—interchangeably, C# uses double quotes for literals or strings and single quotes for data type char.

• C# uses \ as an escape character, embedded in literals; for example, “Prime\r\nExample” indicates that carriage return and line feed separate the two words. C# has verbatim strings; these are prefixed by @ and simply instruct C# to take a literal at face value. For example, with @“Prime\r\nExample”, C# will not interpret \r\n as carriage return and line feed. If you specify a string, say a path as c:\ajay, the options are to write either “c:\\ajay” or @”c:\ajay”. APL+Win does not have embedded escape sequence characters but can pass literals to C# using the C# conventions.

• How many statement delimiters does APL+Win have? It might surprise you to learn that there are two: diamond (ª) and linefeed. C# has a single statement delimiter, semi-colon; statements may span several lines. Unlike APL+Win where these delimiters are optional, the C# delimiter is mandatory.

If you are lured into the belief that C# is difficult, it might be an opportune moment to remind yourself how

difficult APL has been between the time when you started to learn it and the present, when you have mastered the language.

C# is a pleasant experience. From my point of view, C# is no more difficult than APL+Win and the two

languages share a common attribute, namely, it is possible to write code without understanding all the subtleties of the language. Unlike APL+Win, C# has a wealth of sources for worked examples and general reference; therefore, in theory, C# should be easier to learn.

1.2.1.1 Language symbols

This article involves two languages, C# and APL+Win. The context involves the examination of the code side-by-side. As an aid to understanding the code, the following table is useful.

APL+Win C# Description „ = Comes from or becomes

= == Equality comparison

¬ != Not equal to

< < Less than

ˆ <= Less than or equal to (not greater than)

> > Greater than

‰ >= Greater than or equal to (not less than)

| % Modulus

10 In order to keep this simple, I will not elaborate on dynamic localisation here; this does not exist in C#.

Page 11: Linq to Objects 101 Samples C to AplWin

Page 11 of 69

1.2.1.2 What is the question?

The question mark is part of the C# language; it is like an APL+Win primitive. double?[] doubles = { 1.7, 2.3, 4.1, 1.9, null, 2.9 }; In the above line, the question mark indicates that any element of the vector can have a null value. Sign = (MyVal == 0) ? 0 : (MyVal < 0) ? -1 : 1; In the latter example, the question mark indicates ‘if’: read the line as “the sign of a scalar MyVal is 0 if it is

zero, else if it is less than one, the sign is -1 else it has a default value of 1” C# has a data type that is also of interest as it occurs in the code samples: null. C# is a strongly typed

language; APL+Win is a type-inferred language. The null data type is a difficult concept; technically, it means a missing value or that a variable has been declared but not assigned a value.

APL cannot have a variable that is unassigned since it is not a declarative language. However, in some

contexts, 0/0 or 0/’’ are appropriate to emulate a null value in APL+Win—it also has a null value.

1.3 Restriction Operators

This group of operators apply relational criteria to data and return the elements that satisfy the criteria; the key concept is to elicit results using relational operators on lists, or vectors, or arrays, numeric and character. Another way to understand this group of operators is to think of them as filtering an existing object, the argument, and creating a new object, the result.

APL+Win supports the full set of relational operators found in C#; the difference is that LINQ also has

names for some of the operators whereas APL+Win has primitives.

1.3.1 Where - Simple 1

This example shows the selection, from a given vector, of all elements whose value is greater than five.

1.3.1.1 C# code

At the URL, this sample is listed as follows:

public void Linq1()

{

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var lowNums = from n in numbers

where n < 5

Page 12: Linq to Objects 101 Samples C to AplWin

Page 12 of 69

select n;

Console.WriteLine("Numbers < 5:");

foreach (var x in lowNums)

{

Console.WriteLine(x);

}

}

The following is apparent:

• The data that passes for the argument to the function is hard-coded, making it inconvenient, if not impossible, to test the function with alternative data.

• The function does not return a result; it writes to the console. Therefore, it would be impossible to return results to or pass data from APL+Win.

Therefore, in order to overcome these limitations, I have modified the code to read as follows:

public int[] Linq1(int[] numbers, int threshold)

{

var lowNums = from n in numbers

where n < threshold

select n;

return lowNums.ToArray();

}

Now the function will

• Accept two arguments, the data and the threshold that is used to filter the data.

• Return a result instead of printing it to the console.

1.3.1.2 APL+Win code11

All the APL+Win functions assume that the instance of the C# COM DLL exists already and that it is the default left-hand argument of Œwi the function.

’ Z„Linq1;L;R;Linq;APL [1] © RESTRICTION OPERATOR: Where - Simple1 [2] L„¹(2?10)?¨15 © With possible replication [3] R„?10 [4] Linq„Œwi 'Linq1' L R [5] APL„(L<R)/L [6] Z„•œ(›¨'L' 'R' 'LINQ' 'APL' 'Match?'),¨L R Linq APL (Linq−APL) ’

1.3.1.3 Understanding the standard result

The first objective must be to reproduce the results from C#:

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

The APL+Win result, side by side, is:

11 It would be nice if APL+Win retained syntax colouring with copy & paste, as C#!

Page 13: Linq to Objects 101 Samples C to AplWin

Page 13 of 69

The sample shows the results as follows:

On the face of it, the sample shows the result as an n by 1 array whereas the APL equivalent shows it as

a vector of n elements. In fact, the sample is appending a carriage return12

after each element: the results are identical.

1.3.1.4 Method Signature

The previous example illustrates how a method inside the COM is callable from APL+Win with arbitrary arguments. However, you should verify how the signature of a method—how it is coded—before attempting a call.

The syntax of a method may be established by a visual examination of the code—refer to Appendix A

either for code listings—or as follows:

Œwi '?Linq1' XLinq1 method: Result@Array_Long „ ŒWI 'XLinq1' numbers@Array_Long threshold@Long

12 WriteLine appends \r\n (carriage return and line feed) to its argument.

Page 14: Linq to Objects 101 Samples C to AplWin

Page 14 of 69

Note that this query returns both the name and type of each argument, and indicates the type of the result returned, if any.

1.3.1.5 Further tests

The APL+Win function, Linq1, creates random arguments—see lines [2]-[3]—and permits tests to be run quickly.

The following illustrates the results of three further tests.

The argument numbers is listed first (as L), followed by the argument threshold (as R). Then the result

returned by the COM DLL is listed (as Linq), followed by the corresponding result from APL+Win (as APL). The label Matched? shows 1 when the results from C# and APL+Win match else it shows 0.

This concludes the basic guide to reading each of the remaining examples/samples

13.

1.3.2 Where - Simple 2

This query lists all the products that are out of stock. The list or product, unlike the list of customers held in an external XML file, is built using code in DATA.CS. The first two products are built with these lines of code:

C# accesses the individual elements of data by name, shown here in the VS2008 Immediate Window.

13 This is LINQ! an advancement to C#. .APL+Win has done this from inception, has it not?

Page 15: Linq to Objects 101 Samples C to AplWin

Page 15 of 69

This is a complex C# data type; it comprises of several simple C# types. The data structure Product is

build as follows:

public class Product

{

public int ProductID;

public string ProductName;

public string Category;

public decimal UnitPrice;

public int UnitsInStock;

}

In APL+Win, the simplest approach is to code the C# COM DLL to supply the data

14. Everything is

available except that the names of the individual elements.

14 This avoids transcription errors and facilitates comparisons.

Page 16: Linq to Objects 101 Samples C to AplWin

Page 16 of 69

Finally, let us see the results of the LINQ Query in APL+Win:

’ Z„Linq2;L;R;Linq;APL;products [1] © RESTRICTION OPERATOR: Where - Simple 2 [2] Linq„Œwi 'Linq2' [3] products„Œwi 'GetProductListEx' © ProductID ProductName Category

UnitPrice UnitsInStock [4] L„¹¯1†¨products © Last element is UnitsInStock [5] APL„(Œio+1)œ¨(L=0)/products [6] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The results match!

1.3.3 Where - Simple 3

This query selects items from the product list where the number of items in stock is non-zero and the item's unit price is greater than 3.00.

Page 17: Linq to Objects 101 Samples C to AplWin

Page 17 of 69

The results match; they are produced by the following function:

’ Z„Linq3;L;R;Linq;APL;products [1] © RESTRICTION OPERATOR: Where - Simple 3 [2] Linq„Œwi 'Linq3' [3] products„Œwi 'GetProductListEx' © ProductID ProductName Category

UnitPrice UnitsInStock [4] L„¹(Œio+3)œ¨products © Fourth element is UnitPrice [5] R„¹¯1†¨products © Last (fifth) element is UnitsInStock [6] APL„(Œio+1)œ¨((R>0)^L>3)/products [7] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

I am using a screenshot to capture the results of functions, especially where the results are verbose, as in

this instance. This is purely a convenience for formatting the content of this document. For your exploration, you may choose to stop the functions after the penultimate line and then examine or debug the individual components of the results at your leisure; the last line shows the complete results.

How does it work? With C# a two-dimensional string array, potentially, each row has a different length: the

length of the number of characters in it. With APL+Win, all rows have the same length—they are padded with trailing space making up a length equal to the longest string in the array. However, with a nested string vector, each element occupies only enough space to accommodate its own length irrespective of the length of co-existing elements; this feature simplifies string relational comparisons.

1.3.4 Where - Drilldown

This query prints a list of customers from the state of Washington along with their orders. The list of customers holds customers details and their orders.

Linq4 LINQ LAZYK Lazy K Kountry Store 10482 21/03/1997 10545 22/05/1997 TRAIH Trail's Head Gourmet Provisioners 10574 19/06/1997 10577 23/06/1997 10822 08/01/1998 WHITC White Clover Markets 10269 31/07/1996 10344 01/11/1996 10469 10/03/1997 10483 24/03/1997 10504 11/04/1997 10596 11/07/1997 10693 06/10/1997 10696 08/10/1997 10723 30/10/1997 10740 13/11/1997 10861 30/01/1998 10904 24/02/1998 11032 17/04/1998 11066 01/05/1998 APL LAZYK Lazy K Kountry Store 10482 21/03/1997 10545 22/05/1997 TRAIH Trail's Head Gourmet Provisioners 10574 19/06/1997 10577 23/06/1997 10822 08/01/1998 WHITC White Clover Markets 10269 31/07/1996 10344 01/11/1996 10469 10/03/1997 10483 24/03/1997 10504 11/04/1997 10596 11/07/1997 10693 06/10/1997 10696 08/10/1997 10723 30/10/1997 10740 13/11/1997

Page 18: Linq to Objects 101 Samples C to AplWin

Page 18 of 69

10861 30/01/1998 10904 24/02/1998 11032 17/04/1998 11066 01/05/1998 Match? 1

The function is defined as follows:

’ Z„Linq4;Linq;APL [1] © RESTRICTION OPERATOR: Where - DrillDown [2] Linq„œœ¨¨Œwi 'Linq4' [3] APL„Œwi 'GetCustomerListEx' © CustomerID 1,CompanyName

2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[4] APL„(((Œio+4)œ¨APL)¹›'WA')/APL © Just those in the WA Region - <Region> is the fifth element

[5] APL„(Œio+0 1 9)œ¨¨›APL © <CustomerID>, <CustomerName> & <Orders> i.e. First, Second & Tenth element

[6] ((Œio+2)œAPL)„œ¨1 1 0/¨¨(Œio+2)œAPL © <OrderId> & <OrderDate> i.e First & Second element of <Orders>, now the third element

[7] APL„³œAPL [8] Z„('LINQ' 'APL' 'Match?'),[Œio+0.5] Linq APL (Linq−APL) ’

The comments in this function provide valuable clues on the computation of the result. If the logic is not self-evident, you need to examine the function line by line.

The COM method GetCustomerListEx hides a subtlety: because APL+Win does not support the datetime

data type, the method returns the date information as a string, formatted in short date regional format. I am using the UK regional format, that is, dd/mm/yyyy

15. For reporting purposes, this technique is adequate, as it

does not involve any date arithmetic.

1.3.5 Where - Indexed

This query uses an indexed Where clause to print the name of each number, from 0-9, where the length of the number's name is shorter than its value. In this case, the code is passing a lamda expression which is converted to the appropriate delegate type. The body of the lambda expression tests whether the length of the string is less than its index in the array.

At this point, the reality of the C# jargon hits home; as mentioned, it is beyond the scope of the present

objective. Briefly, a lambda expression is an anonymous (one without a name) function and contains statements like any function. For the lambda operator => read “goes to”. A good reference on C# 3.0 is a prime requisite for understanding the Linq to Objects samples: at the very least you need to read the words

accompanying each example at the URL http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx.

Linq5 LINQ five six seven eight nine APL five six seven eight nine Match? 1

The function is defined as follows:

’ Z„Linq5;Linq;APL [1] © RESTRICTION OPERATOR: Where - Indexed [2] Linq„Œwi 'Linq5'

15 Depending on your locale, you may see different results in your session; however, the C# and APL+Win results will both be consistent with your

locale.

Page 19: Linq to Objects 101 Samples C to AplWin

Page 19 of 69

[3] APL„"zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine"

[4] APL„(¹(½¨APL)<(-Œio)+¼½APL)/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.4 Projection Operators

Projection operators transform their argument into new objects, the results; the arguments and results may be of different types. These operators often involve calculation within a selection.

1.4.1 Select - Simple 1

This query returns a sequence of integers one greater than those in an input array; it uses the expression in the select clause to add one to each element in the new sequence. The C# code is: public int[] Linq6()

{

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var numsPlusOne = from n in numbers

select n + 1;

return numsPlusOne.ToArray();

}

APL+Win does not support the facility to select a number and perform an arithmetic operation on that number in one expression. However, APL+Win can produce the same result.

Linq6 LINQ 6 5 2 4 10 9 7 8 3 1 APL 6 5 2 4 10 9 7 8 3 1 Match? 1

The APL function is defined as follows:

’ Z„Linq6;Linq;APL [1] © Projection Operators - Select Simple 1 [2] Linq„Œwi 'Linq6' [3] APL„1+ 5 4 1 3 9 8 6 7 2 0 [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.4.1.1 Linq6 in focus

The alternative or conventional C# way of achieving the same result is:

public int[] Linq6alt()

{

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

int[] res = new int[numbers.Length];

for (int i = 0;i< numbers.Length;i++)

{

res[i]=numbers[i]+0;

}

return res;

}

It is now apparent that this LINQ query simply saves the developer two things: first, an explicit loop and

second the facility to return a subset of the argument vector by the use of a where clause, if necessary. In fact, Linq6 hides a much more important subtlety: if, say, only even numbers are retained from the

argument, the alternative solution will not work since it is impossible to determine how many elements are even without executing another loop to determine it first. Then, the solution to a simple problem is at risk of becoming a clutter of code.

Page 20: Linq to Objects 101 Samples C to AplWin

Page 20 of 69

Of course, the APL solution takes such a restriction in its stride

16:

1+(0=2|APL)/APL„5 4 1 3 9 8 6 7 2 0 5 9 7 3 1

1.4.2 Select - Simple 2

This query returns the name of every product in the product list. The matching APL+Win result comes from the following function:

’ Z„Linq7;Linq;APL [1] © RESTRICTION OPERATOR: Where - Indexed [2] Linq„œŒwi 'Linq7' [3] APL„œ(Œio+1)œ¨Œwi 'GetProductListEx' © ProductID ProductName Category

UnitPrice UnitsInStock. ProductName is second element [4] Z„•(›¨'LINQ' 'APL' 'Match?'),[Œio-0.5]Linq APL (Linq−APL) ’

1.4.3 Select - Transformation

This query returns the name of each number in an integer array by indexing into a second array that contains the names. The C# solution works because it works in index origin zero.

APL+Win can return the same result in index origin one or zero; the result drawn from the C# DLL work in

the only index origin possible, zero, irrespective of the setting in APL+Win.

Œio„1 ª Linq8 LINQ five four one three nine eight six seven two zero APL five four one three nine eight six seven two zero Match? 1 Œio„0 ª Linq8 LINQ five four one three nine eight six seven two zero

16 Unlike C#, APL+Win can resize/reorder arrays dynamically.

Page 21: Linq to Objects 101 Samples C to AplWin

Page 21 of 69

APL five four one three nine eight six seven two zero Match? 1

The APL+Win function is defined as follows:

’ Z„Linq8;Linq;APL [1] © Projection Operators: Select - Transformation [2] Linq„Œwi 'Linq8' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„("zero" "one" "two" "three" "four" "five" "six" "seven" "eight"

"nine" )[APL+Œio] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.4.4 Select - Anonymous Types 1

This query returns each element of its argument in uppercase and lowercase. With APL+Win, I will not use the CharUpper or CharLower Application Programming Interface (API) calls in order to keep the comparison strictly at the language level.

The solution is quite simple: substitute each of the 26 characters with one in the corresponding case.

’ R„L LCase R [1] © Return R in uppercase [2] L„Œio [3] :for i :in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' [4] ((i=,R)/,R)„'abcdefghijklmnopqrstuvwxyz'[L] [5] L„L+1 [6] :endfor ’

’ R„L UCase R [1] © Return R in uppercase [2] L„Œio [3] :for i :in 'abcdefghijklmnopqrstuvwxyz' [4] ((i=,R)/,R)„'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[L] [5] L„L+1 [6] :endfor ’

The following APL+Win function produces a comparison of the solution:

’ Z„Linq9;Linq;APL [1] © Projection Operators - Select - Anonymous Type 1 [2] Linq„Œwi 'Linq9' [3] APL„œ,¨/›¨¨(UCase ¨"aPPLE" "BlUeBeRrY" "cHeRry") (LCase ¨"aPPLE"

"BlUeBeRrY" "cHeRry") [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The results match:

Linq9 LINQ APPLE apple BLUEBERRY blueberry CHERRY cherry APL APPLE apple BLUEBERRY blueberry CHERRY cherry Match? 1

1.4.5 Select - Anonymous Types 2

This query iterates over the elements of an input integer vector and returns the element’s name and parity, that is, whether it is odd or even. It works because string vector holds the digit names in numerical sequence, starting with zero—the index origin in C#.

Page 22: Linq to Objects 101 Samples C to AplWin

Page 22 of 69

The APL+Win function—index origin independent—is:

’ Z„Linq10;Linq;APL [1] © Projection Operators: Select - Anonymous Types 2 [2] Linq„Œwi 'Linq10' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„(›¨("zero" "one" "two" "three" "four" "five" "six" "seven" "eight"

"nine")[Œio+APL]),¨ ›¨('even' 'odd')[Œio+2|APL] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.4.6 Select - Anonymous Types 3

This query returns the name of every product in the product list along with the category of the product and its unit price. The C# version renames UnitPrice to Price. As mentioned, APL+Win identifies elements of a nested array by its cardinal order and not by name.

The APL+Win function that produces a matching result:

’ Z„Linq11;Linq;APL [1] © Projections Operators: Select - Anonymous Types 3 [2] Linq„œŒwi 'Linq11' [3] APL„0 1 1 1 0/œŒwi 'GetProductListEx' © ProductID ProductName Category

UnitPrice UnitsInStock [4] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) [5] …0 [6] (ProductName Category Price)„,›[Œio+1]³APL ’

Note line [6]: APL+Win can easily reclaim the names of the columns in the result: C# retains the names intrinsically and APL+Win assigns them arbitrarily.

1.4.7 Select - Indexed

This query returns the value of each element in a vector of integers whether the element matches its index—in index origin zero—in the vector. The index of each element is inferred rather than index in another vector holding the actual indices. Linq12 LINQ APL Match? 5 0 5 0 1 4 0 4 0 1 0 1 0 3 1 3 1 9 0 9 0 8 0 8 0

Page 23: Linq to Objects 101 Samples C to AplWin

Page 23 of 69

6 1 6 1 7 1 7 1 2 0 2 0 0 0 0 0

Although the results match, there is a deviation in the result: 1 and 0 are shown instead of ‘true’ and

‘false’, respectively. The APL+Win function:

’ Z„Linq12;Linq;APL [1] © Projections Operators: Select Indexed [2] Linq„³œŒwi 'Linq12' [3] APL„³œAPL (APL=(-Œio)+¼½APL„5 4 1 3 9 8 6 7 2 0) [4] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.4.8 Select - Filtered

This query prints the name of each element of an integer vector that is less than five; it combines ‘select’ and ‘where’ to build a simple query that indexes into another string vector that contains the names of the elements. All elements are less than nine.

Linq13 LINQ APL Match? four four 1 one one three three two two zero zero

The function is:

’ Z„Linq13;Linq;APL [1] © Projection Operators: Select - Filtered [2] Linq„œŒwi 'Linq13' [3] APL„"zero" "one" "two" "three" "four" "five" "six" "seven"

"eight" "nine" [4] APL„œAPL[Œio+(5 4 1 3 9 8 6 7 2 0<5)/5 4 1 3 9 8 6 7 2 0] [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.4.9 SelectMany - Compound from 1

This example identifies ordered pairs of integers, such that the first number is an element of one integer vector and the second number is an element of another integer vector where the first number is less than the second number. The query uses a compound ‘from’ clause to compose a query that returns a sequence of the pairs.

’ Z„Linq14;Linq;APL;numbersA;numbersB;Select [1] © Projection Operators: SelectMany - Compound from 1 [2] Linq„³œŒwi 'Linq14' [3] numbersA„0 2 4 5 6 8 9 [4] numbersB„1 3 5 7 8 [5] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [6] APL„(›[Œio+1]numbersA°.<numbersB) Select ¨›numbersB [7] APL„numbersA,¨¨APL [8] APL„³†,/³¨œ¨(¹×½¨APL)/APL [9] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

The results match: LINQ APL Match? 0 1 0 1 1

This query is more complicated than it seems at first sight.

• Elements of the first vector, numbersA, are replicated as many

Page 24: Linq to Objects 101 Samples C to AplWin

Page 24 of 69

0 3 0 3 0 5 0 5 0 7 0 7 0 8 0 8 2 3 2 3 2 5 2 5 2 7 2 7 2 8 2 8 4 5 4 5 4 7 4 7 4 8 4 8 5 7 5 7 5 8 5 8 6 7 6 7 6 8 6 8

times as there are elements in the second vector, numbersB.

• The fact that both vectors are sorted in ascending order is a coincidence; the order is inconsequential.

• Elements from the first vector that are greater than all the elements of the second vector are discarded.

Note the localised function, ‘Select’, that is used by the APL solution. In order to explore the reason why this is necessary, replace ‘Select’ by ‘/’ on line [6] and investigate. Read the result row by row: the first number is less than the second number.

1.4.10 SelectMany - Compound from 2

This query returns all orders whose total is less that 500; each such order is identified by the CustomerID and OrderID. The list of customers holds each CustomerID uniquely but the ‘orders’ details are recurring.

APL+Win solution is:

’ Z„Linq15;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: SelectMany - Compound from 2 [2] Linq„œŒwi 'Linq15' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [4] APL„Œwi 'GetCustomerListEx' © CustomerID

1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] CustomerID„Œioœ¨APL © CustomerID [6] Orders„(››1 0 1) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) without OrderDate 2 [7] APL„(¹¨500>¯1†¨¨Orders) Select ¨Orders © Order Values

below 500 [8] (CustomerID APL)„(›×†¨½¨APL) Select ¨CustomerID APL © Remove those

without qualifying OrderValue [9] APL„œ¨(›¨›¨CustomerID),¨¨APL © Add CustomerID [10] APL„œ,[Œio]/APL © Return as a 3

column array [11] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

The results match. The function Select is localised for the same reasons hinted in the previous example.

You did investigate why this is necessary, didn’t you?

1.4.11 SelectMany - Compound from 3

This query returns all orders made in 1998 or later.

Page 25: Linq to Objects 101 Samples C to AplWin

Page 25 of 69

The APL+Win function that produces the matching result is:

’ Z„Linq16;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: SelectMany - Compound from 3 [2] Linq„œŒwi 'Linq16' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [4] APL„Œwi 'GetCustomerListEx' © CustomerID

1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] CustomerID„Œioœ¨APL © CustomerID [6] Orders„(››1 1 0) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) without OrderValue 3 [7] APL„(¯1†¨¨Orders) © Extract the Order

Date UK Short date format DD/MM/YYYY [8] APL„100ƒ¨¨¨,¨¨¨´¨¨¨(›››100 100 10000)‚¨¨¨Œfi¨¨¨APL~¨¨¨'/' © Convert to

ISO format YYYYMMDD [9] APL„¹¨APL‰19980101 © Selection vector [10] APL„APL Select ¨Orders © Orders on or

after 1 January 1998 [11] (CustomerID APL)„(›×†¨½¨APL) Select ¨CustomerID APL © Remove those

without qualifying OrderValue [12] APL„œ¨(›¨›¨CustomerID),¨¨APL © Add CustomerID [13] APL„œ,[Œio]/APL © Return as a 3

column array [14] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) [15] …0 [16] This involves selection by date, a data type that APL+Win does not

support inherently [17] As this involves a simple date comparison, it is easy to convert the

date to ISO format & use the results as integers ’

The LINQ query specifies all orders made in 1998: for APL+Win, I have interpreted this as meaning on or after first of January 1998. This is necessary because APL+Win lacks the date data type and the supporting functions that return the constituents of a date value such as year, month, etc. Refer to lines [16]-[17] for other details. Although it is quite feasible to write the C# code to return the year for this example, I felt that it was better to keep the function GetCustomerListEx generic—it returns the same result irrespective of the example where it is used.

1.4.12 SelectMany - from Assignment

This query returns all orders where the order total is greater than 2000.00.

Page 26: Linq to Objects 101 Samples C to AplWin

Page 26 of 69

The APL+Win function that returns the result is:

’ Z„Linq17;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: SelectMany - from Assignment [2] Linq„œŒwi 'Linq17' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [4] APL„Œwi 'GetCustomerListEx' © CustomerID

1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] CustomerID„Œioœ¨APL © CustomerID [6] Orders„(››1 0 1) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) without OrderDate 2 [7] APL„(¹¨2000<¯1†¨¨Orders) Select ¨Orders © Order Values

below 500 [8] (CustomerID APL)„(›×†¨½¨APL) Select ¨CustomerID APL © Remove those

without qualifying OrderValue [9] APL„œ¨(›¨›¨CustomerID),¨¨APL © Add CustomerID [10] APL„œ,[Œio]/APL © Return as a 3

column array [11] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) [12] …0 [13] How is the query paradigm different from Linq15? I've included it here

for completeness. ’

Note my comment on line [13].

1.4.13 SelectMany - Multiple from

The LINQ documentation for this example reads as follows: “This sample uses multiple from clauses so that filtering on customers can be done before selecting their orders. This makes the query more efficient by not selecting and then discarding orders for customers outside of Washington.” In other words, customers from within Washington are selected first and then their orders.

The APL+Win function is:

’ Z„Linq18;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: SelectMany - Multiple from [2] Linq„œŒwi 'Linq18' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [4] APL„Œwi 'GetCustomerListEx' © CustomerID

1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] APL„(((Œio+4)œ¨APL)¹›'WA')/APL © Just those in the WA Region - <Region> is the fifth element

[6] CustomerID„Œioœ¨APL © CustomerID [7] Orders„(››1 1 0) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) without OrderValue 3 [8] APL„(¯1†¨¨Orders) © Extract the Order

Date UK Short date format DD/MM/YYYY

Page 27: Linq to Objects 101 Samples C to AplWin

Page 27 of 69

[9] APL„100ƒ¨¨¨,¨¨¨´¨¨¨(›››100 100 10000)‚¨¨¨Œfi¨¨¨APL~¨¨¨'/' © Convert to ISO format YYYYMMDD

[10] APL„¹¨APL‰19970101 © Selection vector [11] APL„APL Select ¨Orders © Orders on or

after 1 January 1998 [12] (CustomerID APL)„(›×†¨½¨APL) Select ¨CustomerID APL © Remove those

without qualifying OrderValue [13] APL„(››1 0) Select ¨¨APL © Drop OrderValue [14] APL„œ¨(›¨›¨CustomerID),¨¨APL © Add CustomerID [15] APL„œ,[Œio]/APL © Return as a 2

column array [16] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) [17] …0 [18] This involves selection by date, a data type that APL+Win does not

support inherently [19] As this involves a simple date comparison, it is easy to convert the

date to ISO format & use the results as integers ’

The results match:

Linq18 LINQ APL Match? LAZYK 10482 LAZYK 10482 1 LAZYK 10545 LAZYK 10545 TRAIH 10574 TRAIH 10574 TRAIH 10577 TRAIH 10577 TRAIH 10822 TRAIH 10822 WHITC 10469 WHITC 10469 WHITC 10483 WHITC 10483 WHITC 10504 WHITC 10504 WHITC 10596 WHITC 10596 WHITC 10693 WHITC 10693 WHITC 10696 WHITC 10696 WHITC 10723 WHITC 10723 WHITC 10740 WHITC 10740 WHITC 10861 WHITC 10861 WHITC 10904 WHITC 10904 WHITC 11032 WHITC 11032 WHITC 11066 WHITC 11066

A simple reminder: short results are shown within the body of the document as text and results that are

long are shown partially as a screenshot—you are invited to run the functions to see the results in full. Also, this document is best viewed with magnification, say 150%, as this renders the screenshots bigger and hence readable with greater ease.

1.4.14 SelectMany - Indexed

This query returns the CustomerID and OrderID for every order in the database—the Customer list. This query is interesting in that it returns the results as formatted text. What if the raw results are required?

Page 28: Linq to Objects 101 Samples C to AplWin

Page 28 of 69

Superficially, the results do not match! However, if you examine the results more closely, C# returns the same result as APL+Win; the difference is in the format. The APL+Win function is:

’ Z„Linq19;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: SelectMany - Indexed [2] Linq„œŒwi 'Linq19' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [4] APL„Œwi 'GetCustomerListEx' © CustomerID

1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] CustomerID„Œioœ¨APL © CustomerID [6] CustomerID„›¨,¨+\(½CustomerID)/1 © Give each

customer it own cardinal number [7] Orders„(››1 0 0) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) Keep OrderID only [8] (CustomerID Orders)„(›0¬¹½¨Orders) Select ¨CustomerID Orders © Remove

those without any Orders [9] APL„œ¨(›¨›¨CustomerID),¨¨Orders © Add CustomerID [10] APL„œ,[Œio]/APL © Return as a 2

column array [11] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.5 Partitioning Operators

This group of operators splice their arguments and return subset as their result

1.5.1 Take - Simple

This query uses ‘Take’ to generate a sequence of the first three elements of an integer vector; note that in this instance, not only do C# LINQ and APL+Win share the jargon but the jargon has an identical meaning in both contexts.

’ Z„Linq20;Linq;APL [1] © Partitioning Operators: Take - Simple [2] Linq„œŒwi 'Linq20' [3] APL„3†5 4 1 3 9 8 6 7 2 0 [4] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

Of course, the results match!

Linq20 LINQ APL Match? 5 4 1 5 4 1 1

1.5.2 Take - Nested

This query returns customer ID, order ID, and order date for the first three orders from customers in Washington. The sample uses ‘Take’ to limit the sequence generated by the query expression to the first three of the orders. The hidden complication is that some customers may have zero orders.

Linq21 LINQ APL Match? LAZYK 10482 21/03/1997 LAZYK 10482 21/03/1997 1 LAZYK 10545 22/05/1997 LAZYK 10545 22/05/1997 TRAIH 10574 19/06/1997 TRAIH 10574 19/06/1997

The function is:

’ Z„Linq21;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: Take - Nested [2] Linq„œŒwi 'Linq21' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’'

Page 29: Linq to Objects 101 Samples C to AplWin

Page 29 of 69

[4] APL„Œwi 'GetCustomerListEx' © CustomerID 1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] APL„(((Œio+4)œ¨APL)¹›'WA')/APL © Just those in the WA Region - <Region> is the fifth element

[6] CustomerID„Œioœ¨APL © CustomerID [7] Orders„(››1 1 0) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) Keep OrderID, OrderDate only [8] (CustomerID Orders)„(›0¬¹½¨Orders) Select ¨CustomerID Orders © Remove

those without any Orders [9] APL„œ¨(›¨›¨CustomerID),¨¨Orders © Add CustomerID [10] APL„œ,[Œio]/APL © Return as a 3

column array [11] APL„œ3†›[Œio+1]APL [12] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

The APL+Win can compute other variations in this query that may also hide complications.

1.5.2.1 First two customers in Washington and all their orders

Assuming that there are more than two customers with orders in Washington:

[9.5] APL„2†APL

[11] © APL„œ3†›[Œio+1]APL

1.5.2.2 First 3 customers in Washington and their first 5 orders

Assuming that there are more than three customers in Washington with orders: note that some customers may have fewer than 5 orders.

[9.5] APL„œ,[Œio]/((3,¨1‡¨ ½¨APL)˜½¨APL)†¨APL © First 3 orders of the first

3 customers in Washington APL [11] © APL„œ3†›[Œio+1]APL

The interesting challenge is in coding C# for these two variations!

1.5.3 Skip - Simple

This query uses ‘Skip’ to get all but the first 4 elements of the array.

Linq22 LINQ APL Match? 9 8 6 7 2 0 9 8 6 7 2 0 1

The APL+Win solution:

’ Z„Linq22;Linq;APL [1] © Partitioning Operators: Skip - Simple [2] Linq„œŒwi 'Linq22' [3] APL„4‡5 4 1 3 9 8 6 7 2 0 [4] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

If there are fewer than four elements in the argument, the C# and APL+Win solutions return matching

results; consider this as an exercise!

1.5.4 Skip - Nested

This query returns all but the first two orders from customers in Washington.

’ Z„Linq23;Linq;APL;Select;CustomerID;Orders [1] © Projection Operators: Skip - Nested [2] Linq„œŒwi 'Linq23' [3] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’'

Page 30: Linq to Objects 101 Samples C to AplWin

Page 30 of 69

[4] APL„Œwi 'GetCustomerListEx' © CustomerID 1,CompanyName 2,Address 3,City 4,Region 5,PostalCode 6,Country 7,Phone 8,Fax 9,Orders 10

[5] APL„(((Œio+4)œ¨APL)¹›'WA')/APL © Just those in the WA Region - <Region> is the fifth element

[6] CustomerID„Œioœ¨APL © CustomerID [7] Orders„(››1 1 0) Select ¨¨(Œio+9)œ¨APL © Orders(OrderID 1,

OrderDate 2, OrderValue 3) Keep OrderID, OrderDate only [8] (CustomerID Orders)„(›0¬¹½¨Orders) Select ¨CustomerID Orders © Remove

those without any Orders [9] APL„œ¨(›¨›¨CustomerID),¨¨Orders © Add CustomerID [10] APL„2 0‡œ,[Œio]/APL © Return as a 3

column array [11] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

Linq23 LINQ APL Match? TRAIH 10574 19/06/1997 TRAIH 10574 19/06/1997 1 TRAIH 10577 23/06/1997 TRAIH 10577 23/06/1997 TRAIH 10822 08/01/1998 TRAIH 10822 08/01/1998 WHITC 10269 31/07/1996 WHITC 10269 31/07/1996 WHITC 10344 01/11/1996 WHITC 10344 01/11/1996 WHITC 10469 10/03/1997 WHITC 10469 10/03/1997 WHITC 10483 24/03/1997 WHITC 10483 24/03/1997 WHITC 10504 11/04/1997 WHITC 10504 11/04/1997 WHITC 10596 11/07/1997 WHITC 10596 11/07/1997 WHITC 10693 06/10/1997 WHITC 10693 06/10/1997 WHITC 10696 08/10/1997 WHITC 10696 08/10/1997 WHITC 10723 30/10/1997 WHITC 10723 30/10/1997 WHITC 10740 13/11/1997 WHITC 10740 13/11/1997 WHITC 10861 30/01/1998 WHITC 10861 30/01/1998 WHITC 10904 24/02/1998 WHITC 10904 24/02/1998 WHITC 11032 17/04/1998 WHITC 11032 17/04/1998 WHITC 11066 01/05/1998 WHITC 11066 01/05/1998

1.5.5 TakeWhile - Simple

This query uses ‘TakeWhile’ to generate return all elements from a numeric vector until elements are less than 6. From an APL+Win point of view, this query is trivial.

Linq24 LINQ APL Match? 5 4 1 3 5 4 1 3 1

’ Z„Linq24;Linq;APL [1] © Partitioning Operators: TakeWhile - Simple [2] Linq„œŒwi 'Linq24' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„(^\APL<6)/APL [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.5.6 TakeWhile - Indexed17

This query uses ‘TakeWhile’ to return elements of a numeric vector, starting from the beginning of the vector until a number is hit that is less than its position in the vector: remember that C# works in index origin 0.

17 This is missing in the links, shown at the start, at http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx

Page 31: Linq to Objects 101 Samples C to AplWin

Page 31 of 69

LINQ APL Match? 5 4 5 4 1

’ Z„Linq25;Linq;APL [1] © Partitioning Operators: TakeWhile - Indexed [2] Linq„œŒwi 'Linq25' [3] APL„(^\APL>(APL¼APL)-Œio)/APL„5 4 1 3 9 8 6 7 2 0 [4] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.5.7 SkipWhile - Simple

This query returns all of the elements of an integer vector, skipping elements until one of them is divisible by three. LINQ APL Match? 3 9 8 6 7 2 0 3 9 8 6 7 2 0 1

’ Z„Linq26;Linq;APL [1] © Partitioning Operators: SkipWhile - Simple [2] Linq„œŒwi 'Linq26' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„(Ÿ\0=3|APL)/APL [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.5.8 SkipWhile - Indexed

This query returns all of the elements of an integer vector, skipping elements until the element's value is less that its position in the array: remember that C# works in index origin 0.

Linq27 LINQ APL Match? 1 3 9 8 6 7 2 0 1 3 9 8 6 7 2 0 1

’ Z„Linq27;Linq;APL [1] © Partitioning Operators: SkipWhile - Indexed [2] Linq„œŒwi 'Linq27' [3] APL„(Ÿ\APL<(-Œio)+¼½APL)/APL„5 4 1 3 9 8 6 7 2 0 [4] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.6 Ordering Operators

This group of operators re-order or sort their arguments according to different criteria. They include simple, even trivial, examples that illustrate principles. Further refinement to the techniques is necessary to build re-usable code that incorporates the same techniques.

1.6.1 OrderBy - Simple 1

This query demonstrates a simple alphabetical sort. Although the example does not demonstrate this, the sorting is case insensitive: I have added a word in upper case to the argument to demonstrate.

Linq28 LINQ APL Match? apple apple 1 ASKOOLUM ASKOOLUM blueberry blueberry cherry cherry

’ Z„Linq28;Linq;APL [1] © Ordering Operators: OrderBy - Simple 1 [2] Linq„œŒwi 'Linq28' [3] APL„"cherry" "apple" "blueberry" "ASKOOLUM" © Case insensitive [4] APL„œAPL[“Œav¼œLCase ¨APL]

Page 32: Linq to Objects 101 Samples C to AplWin

Page 32 of 69

[5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.6.2 OrderBy - Simple 2

This query returns its vector argument sorted in ascending order of the length of each element.

Linq29 LINQ APL Match? apple apple 1 cherry cherry blueberry blueberry

The function:

’ Z„Linq29;Linq;APL [1] © Ordering Operators: OrderBy - Simple 2 [2] Linq„œŒwi 'Linq29' [3] APL„"cherry" "apple" "blueberry" [4] APL„œAPL[”' '+.=³œAPL] [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.6.3 OrderBy - Simple 3

This query returns all of the products sorted alphabetically by the product name.

This result is interesting: it does not match!

’ Z„Linq30;Linq;APL [1] © Ordering Operators: OrderBy - Simple 3 [2] Linq„œŒwi 'Linq30' [3] APL„Œwi 'GetProductListEx' © ProductID ProductName Category UnitPrice

UnitsInStock [4] APL„(œAPL)[“Œav¼œ(Œio+1)œ¨APL;] [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.6.3.1 Where is the difference?

On stopping the function after line [4] and running a query to isolate the differences yields:

Page 33: Linq to Objects 101 Samples C to AplWin

Page 33 of 69

The results match in terms of the number of rows. The difference lies with the character data. C# sorts the

results and passes it to APL+Win; it also passes the raw data to APL+Win. There is loss of accuracy arising from the lack of support for Unicode in APL+Win; in contrast, C# uses Unicode. APL+Win is sorting the data after the loss of accuracy whereas it is the C# result—not the data—that suffers the same loss.

1.6.4 OrderBy - Comparer

This example returns a string vector sorted according to a case insensitive alphanumeric sort.

Linq31 LINQ AbAcUs aPPLE BlUeBeRrY bRaNcH cHeRry ClOvEr APL AbAcUs aPPLE BlUeBeRrY bRaNcH cHeRry ClOvEr Match? 1

The APL+Win function:

’ Z„Linq31;Linq;APL [1] © Ordering Operators - OrderBy - Comparer [2] Linq„Œwi 'Linq31' [3] APL„"aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry" [4] APL„APL[“Œav¼UCase œAPL] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

In order to keep the results comparable, I have not used any API calls in the APL+Win solution.

1.6.5 OrderByDescending - Simple 1

This query returns a vector of floating point numbers sorted in descending order. Linq32 LINQ 4.1 2.9 2.3 1.9 1.7 APL 4.1 2.9 2.3 1.9 1.7 Match? 1.0

The function:

’ Z„Linq32;Linq;APL [1] © Ordering Operators - OrderByDescending - Simple 1 [2] Linq„Œwi 'Linq32' [3] APL„1.7 2.3 1.9 4.1 2.9 [4] APL„APL[”APL] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.6.6 OrderByDescending - Simple 2

This query returns a list of products sorted by the number of units of each product that are in stock.

Page 34: Linq to Objects 101 Samples C to AplWin

Page 34 of 69

The APL+Win function:

’ Z„Linq33;Linq;APL [1] © Ordering Operators - OrderByDescending - Simple 2 [2] Linq„œŒwi 'Linq33' [3] APL„Œwi 'GetProductListEx' [4] APL„œAPL[”(Œio+4)œ¨Œwi 'GetProductListEx'] © ProductID ProductName

Category UnitPrice UnitsInStock [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.6.7 OrderByDescending - Comparer

This query returns a vector of strings sorted alphabetically in descending order, using a case insensitive comparison.

Linq34 LINQ ClOvEr cHeRry bRaNcH BlUeBeRrY aPPLE AbAcUs APL ClOvEr cHeRry bRaNcH BlUeBeRrY aPPLE AbAcUs Match? 1

The APL+Win function:

’ Z„Linq34;Linq;APL [1] © Ordering Operators - OrderByDescending - Comparer [2] Linq„Œwi 'Linq34' [3] APL„"aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry" [4] APL„APL[”Œav¼LCase œAPL] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.6.8 ThenBy - Simple

This sample uses a compound ‘orderby’ to sort a list of digits first by length of their name, and then alphabetically.

Linq35 LINQ one six two five four nine zero eight seven three APL one six two five four nine zero eight seven three Match? 1

’ Z„Linq35;Linq;APL [1] © Ordering Operators - ThenBy - Simple [2] Linq„Œwi 'Linq35' [3] APL„"zero" "one" "two" "three" "four" "five" "six" "seven"

"eight" "nine" [4] APL„APL[“Œav¼LCase œAPL] [5] APL„APL[“¹½¨APL] [6] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Page 35: Linq to Objects 101 Samples C to AplWin

Page 35 of 69

1.6.9 ThenBy - Comparer

This sample prints an array of string values sorted first by length, then sorted alphabetically, using a case-insensitive comparison.

’ Z„Linq36 words;Linq;APL [1] © Ordering Operators - ThenBy - Comparer [2] Linq„Œwi 'Linq36' words [3] words„words[“Œav¼LCaseœwords] [4] APL„words[“¹½¨words] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) [6] …0 [7] Linq36 "aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry" [8] Linq36 "zero" "oNe" "TWo" "tHRee" "foUR" "FIVE" "sIx" "SEVEn"

"eigHt" "NIne" "TEn" "HundRED" ’

1.6.10 ThenByDescending - Simple

This sample uses a compound ‘orderby’ to sort a list of products, first by category in ascending order, and then by unit price in descending order.

’ Z„Linq37;Linq;APL [1] © Ordering Operators - ThenByDescending - Simple [2] Linq„œŒwi 'Linq37' [3] APL„Œwi 'GetProductListEx' [4] APL„œAPL[(”(Œio+3)œ¨APL)[“Œav¼œ ((Œio+2)œ¨APL) [”(Œio+3)œ¨APL]]] [5] Z„(›¨'LINQ' 'APL' 'Match?'),[Œio-0.5]Linq APL (Linq−APL) [6] …0 [7] © Take it a little slower! [8] APL„Œwi 'GetProductListEx' © Get the Product List [9] UnitPrice„(Œio+3)œ¨APL © UnitProce is the 4th element [10] Category„(Œio+2)œ¨APL © Category is the 3rd element [11] APL„œAPL[(”UnitPrice)[“Œav¼œCategory[”UnitPrice]]] ’

1.6.11 ThenByDescending - Comparer

This sample uses an ‘OrderBy’ and a ‘ThenBy’ clause with a custom comparer to sort first by word length and then by a case-insensitive descending sort of the words in an array.

Page 36: Linq to Objects 101 Samples C to AplWin

Page 36 of 69

’ Z„Linq38 words;Linq;APL [1] © Ordering Operators: ThenByDescending - Comparer [2] Linq„Œwi 'Linq38' words [3] words„words[“Œav¼LCase œwords] [4] APL„words[²”¹½¨words] [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) [6] …0 [7] Linq38 "aPPLE" "AbAcUs" "bRaNcH" "BlUeBeRrY" "ClOvEr" "cHeRry" [8] Linq36 "zero" "oNe" "TWo" "tHRee" "foUR" "FIVE" "sIx" "SEVEn"

"eigHt" "NIne" "TEn" "HundRED" ’

1.6.12 Reverse

This query returns a list strings from an input string vector where each element has the second letter 'i'. The output list the elements in reverse order. The sample uses a query operator to gather the elements that have 'i' as the second letter and then reverses the sequence using the Reverse method.

Linq39 LINQ nine eight six five APL nine eight six five Match? 1

’ Z„Linq39;Linq;APL [1] © Ordering Operators: ThenByDescending - Comparer [2] words„"zero" "one" "two" "three" "four" "five" "six" "seven"

"eight" "nine" [3] Linq„Œwi 'Linq39' words [4] APL„²(¹'i'=1†¨1‡¨words)/words [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) [6] …0 [7] APL„²(¹'i'Ÿ.¹¨words)/words © to pick up words with at least one 'i'

anywhere [8] APL„²(¹'io'Ÿ.º¨words)/words © to pick up words with at least one

substring 'io' anywhere ’

1.7 Grouping Operators

This group of operators collates elements contiguously depending on applicable criteria.

1.7.1 GroupBy - Simple 1

This query uses group by to partition a list of numbers by their remainder when divided by 5.

Linq40 LINQ APL Match? 5 0 5 0 1 0 0 0 0 4 4 4 4 9 4 9 4 1 1 1 1 6 1 6 1

Page 37: Linq to Objects 101 Samples C to AplWin

Page 37 of 69

3 3 3 3 8 3 8 3 7 2 7 2 2 2 2 2

The following function produces the matching result:

’ Z„Linq40;L;R;Linq;APL [1] © Grouping Operators: GroupBy - Simple 1 [2] Linq„³Œwi 'Linq40' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] L„5|APL [5] R„((L¼L)=¼½L)/L [6] (APL L)„œ¨(›“R¼L)Þ¨¨›¨L APL [7] APL„³œL APL [8] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.7.2 GroupBy - Simple 2

This sample partitions a vector of words into groups according to the first letter of each word. Linq41 LINQ APL Match? b blueberry b blueberry 1 b banana b banana c chimpanzee c chimpanzee c cheese c cheese a abacus a abacus a apple a apple

’ Z„Linq41;L;R;Linq;APL [1] © Grouping Operators: GroupBy - Simple 2 [2] Linq„³Œwi 'Linq41' [3] APL„"blueberry" "chimpanzee" "abacus" "banana" "apple" "cheese" [4] L„1†¨APL [5] R„((L¼L)=¼½L)/L [6] (L APL)„ œ¨(›“R¼L)Þ¨¨›¨L APL [7] APL„³œL APL [8] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.7.3 GroupBy - Simple 3

This sample uses group by to partition a list of products by category. Coding the C# method to return the result to APL+Win was nothing short of an unpleasant ordeal, given the simplicity of the query.

The APL function:

’ Z„Linq42;Linq;APL;Category;SelectByCategory;Select [1] © Grouping Operators - Simple 3 [2] Linq„Œwi 'Linq42' © œœ¨¨Œwi 'Linq42' [3] APL„Œwi 'GetProductListEx' [4] 0 0½Œdef '’ Z„L Select R',Œtcnl,'[1] Z„L/R ’' [5] Category„(Œio+2)œ¨APL [6] DistinctCategory„((Category¼Category)=¼½Category)/Category [7] SelectByCategory„›[Œio+1](DistinctCategory)°.−Category [8] APL„((›¨DistinctCategory),¨›¨SelectByCategory Select ¨›APL) [9] Z„(œœ¨¨Linq) (œœ¨¨APL) [10] Z„(›¨'APL' 'Linq' 'Match?'),[Œio-0.5]Z ,›(Linq−APL) ’

Page 38: Linq to Objects 101 Samples C to AplWin

Page 38 of 69

You will need to run the query in order to see the detail of the result. As an aside, this illustrates the possibilities of created nested variables in C# in ways that make them compatible with ones in APL+Win.

1.7.4 GroupBy - Nested

1.7.5 GroupBy – Comparer

This query and the next one delivers the same functionality as the next one except in one respect: it does not convert the result to uppercase. It also suffers from the same deficiencies Linq44 LINQ APL Match? from from FORM 0 salt last salt last earn near earn near FORM

The comparison fails since I have corrected the anomalies of the C# solution when coding the APL+Win

function:

’ Z„Linq44;Linq;APL [1] © Grouping Operators - GroupBy - Comparer [2] Linq„œŒwi 'Linq44' [3] APL„" from " " salt " " earn " "last" "near" "FORM" [4] APL„(+/¨^\¨ ' '=¨APL)‡¨APL [5] APL„(-+/¨^\¨²¨' '=¨APL)‡¨APL [6] a„((a¼a)=¼½a)/a„¹LCase ¨APL [7] b„(›¨“¨(›a)¼¨LCase ¨APL)Þ¨LCase ¨APL [8] c„b¼b [9] APL„œ(›[Œio+1]((c=¼½c)/c)°.=c)Select ¨›APL [10] Z„(›¨'LINQ' 'APL' 'Match?'),[Œio-0.5]Linq APL (Linq−APL) ’

1.7.6 GroupBy – Comparer, Mapped

This sample displays which elements from an input string array have the same letters. The sample used GroupBy and an AnagramEqualityComparer class to group the elements into those with the same letters. Note the conversion to uppercase.

The C# sample solution is deficient! In order to illustrate this I have added two more pairs of phrases to

the arguments used in the sample.

Linq45 LINQ APL Match? FROM FORM FROM FORM 0

Page 39: Linq to Objects 101 Samples C to AplWin

Page 39 of 69

SALT LAST SALT LAST EARN NEAR EARN NEAR AJAY AJAY ASKOOLUM ASKOOLUM DEBIT CARD DEBIT CARD BAD CREDIT BAD CREDIT OWLS SLOW SLOW OWLS

The C# solution fails to allow for embedded spaces, although it does trim leading and trailing spaces,

which should be inconsequential in finding anagrams. The C# solution also fails to cope with the case of the phrases, although it converts the result—not the

arguments—to uppercase. The APL+Win solution, which corrects the C# deficiencies, is:

’ Z„Linq45;Linq;APL [1] © Grouping Operators - GroupBy - Comparer, Mapped [2] Linq„œŒwi 'Linq45' [3] APL„UCase¨ " from " " salt " " earn " "last" "near" "FORM" "ajay"

"askoolum" "Debit Card" "Bad Credit" "OWLS" "slow" [4] APL„(+/¨^\¨ ' '=¨APL)‡¨APL [5] APL„(-+/¨^\¨²¨' '=¨APL)‡¨APL [6] a„((a¼a)=¼½a)/a„¹APL [7] b„ (›¨“¨(›a)¼¨APL)Þ¨APL [8] c„b¼b [9] APL„œ(›[Œio+1]((c=¼½c)/c)°.=c)Select ¨›APL [10] Z„(›¨'LINQ' 'APL' 'Match?'),[Œio-0.5]Linq APL (Linq−APL) ’

1.8 Set Operators

As the name implies, this group of operators apply to vectors of numbers or literals. APL+Win is naturally disposed to excel in this context.

1.8.1 Distinct - 1

The sample creates a sequence of unique factors by using the Distinct method on the integer vector of factors to remove duplicates. Linq46 LINQ 2 3 5 APL 2 3 5 Match? 1

’ Z„Linq46;Linq;APL [1] © Set Operators: Distinct - 1 [2] Linq„Œwi 'Linq46' (R„2 2 3 5 5) [3] APL„((R¼R)=¼½R)/R [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) [5] …0 [6] Linq46 2 2 3 5 5 © Original example [7] Linq46 9 8 7 6 2 1 2 3 9 8 7 6 5 2 3 4 5 9 0 8 71 ’

I have coded t he C# method to accept any arbitrary but compatible argument .

Linq46 9 8 7 6 2 1 2 3 9 8 7 6 5 2 3 4 5 9 0 8 71 LINQ 2 3 5 9 8 7 6 2 1 2 3 9 8 7 6 5 2 3 4 5 9 0 8 71 APL 2 3 5 Match? 1

1.8.2 Distinct - 2

This query returns the unique Category names by first selecting all of the category names from the product list, then using Distinct to remove duplicate names.

Page 40: Linq to Objects 101 Samples C to AplWin

Page 40 of 69

Linq47 LINQ APL Match? Beverages Beverages 1 Condiments Condiments Produce Produce Meat/Poultry Meat/Poultry Seafood Seafood Dairy Products Dairy Products Confections Confections Grains/Cereals Grains/Cereals

The APL+Win function:

’ Z„Linq47;Linq;APL [1] © Set Operators: Distinct - 2 [2] Linq„œŒwi 'Linq47' [3] APL„(Œio+2)œ¨Œwi 'GetProductListEx' © ProductID ProductName Category

UnitPrice UnitsInStock [4] APL„œ((APL¼APL)=¼½APL)/APL [5] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.8.3 Union - 1

This query returns the unique elements of two integer arrays. The sample uses the Union method to create a sequence that is a union of the two integer arrays with duplicate elements removed.

’ Z„Linq48;L;R;Linq;APL [1] © Set Operators: Union - 1 [2] L„¹(2?10)?¨15 © With possible replication [3] R„¹(2?10)?¨23 © With possible replication [4] Linq„Œwi 'Linq48' L R [5] L„((L¼L)=¼½L)/L [6] R„((R¼R)=¼½R)/R [7] APL„L,R~L [8] Z„•œ(›¨'L' 'R' 'LINQ' 'APL' 'Match?'),¨L R Linq APL (Linq−APL) ’

This function is coded to use random arguments; therefore, it will return a different result simply because

the argument is different.

1.8.4 Union - 2

This query returns unique letters from Product and Customer names. The sample creates a sequence of product first characters, a sequence of customer first characters, and then joins the two sets by using Union to merge them and remove duplicates.

Linq49 LINQ APL Match? C C 1 A A G G

’ Z„Linq49;L;R;Linq;APL

[1] © Set Operators: Union - 2

[2] Linq„œŒwi 'Linq49'

[3] © (ProductID ProductName Category UnitPrice

Page 41: Linq to Objects 101 Samples C to AplWin

Page 41 of 69

U U N N M M I I Q Q K K T T P P S S R R B B J J Z Z V V F F E E W W L L O O D D H H

UnitsInStock) (© CustomerID CompanyName Address City Region PostalCode Country Phone Fax Orders[])

[4] L„1†¨(Œio+1)œ¨Œwi 'GetProductListEx'

[5] R„1†¨(Œio+1)œ¨Œwi 'GetCustomerListEx'

[6] L„((L¼L)=¼½L)/L

[7] R„((R¼R)=¼½R)/R

[8] APL„œL,R~L

[9] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL)

1.8.5 Intersect - 1

This query returns a list of numbers that are common to two integer vectors. The sample uses Intersect to create one sequence that contains the common values shared by vectors. Linq50 L 3 5 13 0 10 6 4 8 R 12 2 2 22 9 4 13 21 8 LINQ 13 4 8 APL 13 4 8 Match? 1

The APL+Win function : ’ Z„Linq50;L;R;Linq;APL [1] © Set Operators: Intersect - 1 [2] L„¹(2?10)?¨15 © With possible replication [3] R„¹(2?10)?¨23 © With possible replication [4] Linq„Œwi 'Linq50' L R [5] APL„(L¹R)/L [6] APL„((APL¼APL)=¼½APL)/APL [7] Z„•œ(›¨'L' 'R' 'LINQ' 'APL' 'Match?'),¨L R Linq APL (Linq−APL) [8] …0 [9] (L R)„(0 2 4 5 6 8 9) (1 3 5 7 8) ’ This function generates its arguments randonmly and uses each such argument and passes the same

argument to the C# method. The original arguments uses in the sample are shown in line [9].

1.8.6 Intersect - 2

This query returns the letters that are both the first letter of a Product name and the first letter of a Customer name. The sample uses query statements to create two sequence - the first letters of Product names and the first letter of Customer names, then uses Intersect to create a sequence of letters common to both.

Linq51 LINQ APL Match? C C 1 A A G G N N

’ Z„Linq51;L;R;Linq;APL

[1] © Set Operators: Intersect - 2

[2] Linq„œŒwi 'Linq51'

[3] © (ProductID ProductName Category UnitPrice UnitsInStock) (© CustomerID CompanyName Address City Region PostalCode Country Phone

Page 42: Linq to Objects 101 Samples C to AplWin

Page 42 of 69

M M I I Q Q K K T T P P S S R R B B V V F F E E W W L L O O

Fax Orders[])

[4] L„1†¨(Œio+1)œ¨Œwi 'GetProductListEx'

[5] R„1†¨(Œio+1)œ¨Œwi 'GetCustomerListEx'

[6] APL„(L¹R)/L

[7] APL„œ((APL¼APL)=¼½APL)/APL

[8] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL)

1.8.7 Except - 1

This query returns numbers that are in one integer array, but not another. The sample uses Except to create a sequence that contains the values from numbersA that are not also in numbersB.

Linq52 L 9 11 7 0 3 12 8 R 12 2 18 22 0 19 5 LINQ 9 11 7 3 8 APL 9 11 7 3 8 Match? 1

’ Z„Linq52;L;R;Linq;APL [1] © Set Operators: Except 1 [2] L„¹(2?10)?¨15 © With possible replication [3] R„¹(2?10)?¨23 © With possible replication [4] Linq„Œwi 'Linq52' L R [5] L„((L¼L)=¼½L)/L [6] APL„(~L¹R)/L [7] Z„•œ(›¨'L' 'R' 'LINQ' 'APL' 'Match?'),¨L R Linq APL (Linq−APL) [8] …0 [9] (L R)„(0 2 4 5 6 8 9)(1 3 5 7 8) ’

1.8.8 Except - 2

This query returns the first character of product names that are not also the first character of customer names. After getting the first characters of product and customer names using query expressions, the sample uses Except to create a sequence of product characters that doesn't include first characters of customer names.

Linq53 LINQ APL Match? U U 1 J J Z Z

’ Z„Linq53;L;R;Linq;APL [1] © Set Operators: Except - 2 [2] Linq„œŒwi 'Linq53' [3] © (ProductID ProductName Category UnitPrice UnitsInStock) (© CustomerID

CompanyName Address City Region PostalCode Country Phone Fax Orders[]) [4] L„1†¨(Œio+1)œ¨Œwi 'GetProductListEx' [5] R„1†¨(Œio+1)œ¨Œwi 'GetCustomerListEx' [6] L„((L¼L)=¼½L)/L [7] APL„œ(~L¹R)/L [8] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

Page 43: Linq to Objects 101 Samples C to AplWin

Page 43 of 69

1.9 Conversion Operators

From an APL+Win point of view, this group of operators contain trivial examples. However, in a C# context, the examples illustrate the ease with which several operations can be carries out seamlessly using LINQ techniques. The other purpose of these examples is too illustrate the conversion from one complex type to another: APL+Win does not support complex types but can reproduce the results quite easily.

1.9.1 To Array

This sample generates a vector of double values by first using a query expression with orderby to create a sorted sequence of doubles, then ToArray to generate an array from the sequence. Linq54 LINQ 4.1 2.3 1.7 APL 4.1 2.3 1.7 Match? 1.0

The APL+Win function:

’ Z„Linq54;Linq;APL [1] © Conversion Operators: To Array [2] APL„1.7 2.3 1.9 4.1 2.9 [3] Linq„Œwi 'Linq54' APL [4] APL„(2|+\(½APL)/1)/APL[”APL] © Œio independent [5] Z„œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Note that the value for ‘Match’ is shown as a double: this is a consequence of line [5], that is of formatting the result. It is Boolean as you would expect.

1.9.2 To List

This sample generates an array of string values by first using a query expression with orderby to create a sorted sequence of strings from a string array, then toList to generate a List from the sequence. The conversion operation is from an array to a list.

Linq55 LINQ apple blueberry cherry APL apple blueberry cherry Match? 1 The APL+Win function:

’ Z„Linq55;Linq;APL [1] © Conversion Operators: To List [2] Linq„Œwi 'Linq55' [3] APL„"cherry" "apple" "blueberry" [4] APL„APL[“Œav¼œAPL] [5] Z„œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.9.3 To Dictionary

This sample uses anonymous types to create a data structure of people and their scores. It then uses ToDictionary to generate a dictionary from the sequence and its key expression.

A Dictionary is a complex data type in C#. Essentially, it is a name/value pair array with a notable

difference: the array is indexed by the name and not an ordinal value that would represent an index. For example:

Console.WriteLine("Bob's score: {0}", scoreRecordsDict["Bob"]); This yields the following result: Bob's score: {Name=Bob, Score=40}

Page 44: Linq to Objects 101 Samples C to AplWin

Page 44 of 69

This is not available in APL+Win; however, it is quite straightforward to simulate the same effect.

Linq56 LINQ Bob 40 APL Bob 40 Match? 1

’ Z„Linq56;Linq;APL [1] © Conversion Operators: To Dictionary [2] Linq„Œwi 'Linq56' [3] APL„("Alice" 50) ("Bob" 40) ("Cathy" 45) [4] APL„,œ((›"Bob") −¨†¨APL)/APL [5] Z„œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.9.4 OfType

This sample uses OfType to return only the elements of the array that are of type double. This sample is rather tricky for APL+Win: C# recognises a double number when a decimal point is

present, even when the decimal part is zero. In many situations, APL+Win silently converts any number with a decimal part of zero to an integer. The objective is to identify elements of different types: for convenience, I have altered the decimal part of doubles in the argument of this operator to a non-zero value.

Linq57 LINQ 1.1 7.1 APL 1.1 7.1 Match? 1.0

’ Z„Linq57;Linq;APL [1] © Conversion Operators: OfType [2] Linq„Œwi 'Linq57' [3] APL„(0/0) 1.1 "two" 3 "four" 5 "six" 7.1 [4] APL„(645=Œdr ¨APL)/APL [5] Z„œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.10 Element Operators

This group of operators illustrate techniques for working with elements of vectors. This group contains trivial examples, which are valuable nonetheless in one vital respect: when studying the examples, consider the comparative readability of the C# and APL+Win code.

1.10.1 First - Simple

This sample uses ‘First’ to return the first matching element as a Product, instead of as a sequence containing a Product; a Product is a complex data type containing named data items, in this case, ProductID, ProductName, Category, UnitPrice, and UnitsInStock

Linq58 LINQ 12 Queso Manchego La Pastora Dairy Products 38 86 APL 12 Queso Manchego La Pastora Dairy Products 38 86 Match? 1

This function produces the matching result:

Page 45: Linq to Objects 101 Samples C to AplWin

Page 45 of 69

’ Z„Linq58;Linq;APL [1] © Element Operators: First - Simple [2] Linq„Œwi 'Linq58' [3] APL „Œwi 'GetProductListEx' [4] APL„,œ(<\12=Œioœ¨APL)/APL [5] Z„œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Note that this query returns only the first matching element.

1.10.2 First – Condition (missing at URL)

This sample uses ‘First’ to find the first element in a vector that starts with 'o'.

Linq59 LINQ one APL one Match? 1

The function:

’ Z„Linq59;Linq;APL [1] © Element Operators: First - Condition [2] Linq„Œwi 'Linq59' [3] APL„ "zero" "one" "two" "three" "four" "five" "six" "seven" "eight"

"nine" [4] APL„†(¹'o'=†¨APL)/APL [5] Z„(›¨'LINQ' 'APL' 'Match?'),¨,¨Linq APL (Linq−APL) ’

1.10.3 First - Indexed

This example returns the first element of an integer vector that is both even and exists at an even index within the vector. The code sample, as given at the URL, does not work! The culprit line is: int evenNum = numbers.First((num, index) => (num % 2 == 0) && (index % 2 == 0));

It generates the following error:

Delegate 'System.Func<int,bool>' does not take '2' arguments I can only surmise that Microsoft published the code sample prior to the release of C# 3.0. The corrected

line that produces the expected result is:

int evenNum = numbers.Where((num, index) => (num % 2 == 0) && (index % 2 == 0)).First();

The APL function is:

’ Z„Linq60;Linq;APL [1] © Element Operators: First - Indexed [2] Linq„œŒwi 'Linq60' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„†((~2|APL)^~2|(-Œio)+APL¼APL)/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The matching result is:

Linq60 LINQ 6 APL 6 Match? 1

1.10.4 FirstOrDefault - Simple

This query returns the default value of a data type; the example uses the integer data type whose default value is 0. This is possible only in a declarative language such as C#; APL is not a declarative language.

’ Z„Linq61;Linq;APL

Page 46: Linq to Objects 101 Samples C to AplWin

Page 46 of 69

[1] © Element Operators: FirstOrDefault - Simple [2] Linq„œŒwi 'Linq61' [3] © Create a variable from which the data type integer (323) can be

inferred [4] APL„9 10 [5] © Create an empty value from the variable - this emulates declaration [6] APL„0/APL [7] © Take the first or default value [8] APL„†APL [9] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

However, it is possible to demonstrate the concept using APL+Win, using inference.

1.10.5 FirstOrDefault - Condition

This query uses ‘FirstOrDefault’ to return the first product whose ProductID is 789; if there is no match, null is returned. Given the lack of support for the null data type in APL+Win, it is straightforward to modify the method to return true or false.

Linq62 LINQ 0 APL 0 Match? 1

The function:

’ Z„Linq62;Linq;APL [1] © Element Operators: FirstOrDefault - Condition [2] Linq„œŒwi 'Linq62' [3] APL„789¹Œioœ¨Œwi 'GetProductListEx' © First element is ProductID [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.10.6 FirstOrDefault - Indexed

This query uses ‘FirstOrDefault’ to find the first number in a vector that is within 0.5 of its position in the vector and returns either the first match or the default value of data type double, which is null.

This one is tricky! Not least because the sample code at the URL does not work. Even with correction, it still presents two problems for APL+Win:

• It does not recognise a method in a COM DLL that returns null.

• A vector cannot contain a null value that is recognisable as null by the COM Server. I propose a workaround: I will modify the query to return either the first number from its argument that is

between -0.5 and 0.5 of its position—remember the position is in index origin zero—or return the smallest number if none is found.

Page 47: Linq to Objects 101 Samples C to AplWin

Page 47 of 69

Let us explore the deliverable without null values, without recourse to the COM Server, and with the following APL+Win function:

’ Z„Linq63Ex APL [1] © Element Operators: FirstOrDefault - Indexed [2] © Linq„œŒwi 'Linq63' [3] © APL„1.7 2.3 4.1 1.9 2.9 [4] APL„(0=+/×(³¯0.5 0.5°.+(-Œio)+¼½APL)-[Œio]APL)/APL [5] :if 0=½APL [6] Z„˜/Ð [7] :else [8] Z„нAPL [9] :endif [10] ©Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The APL+Win that delivers the same solution as the COM method—subject to the limitations discussed—

is as follows:

’ Z„Linq63;Linq;APL [1] © Element Operators: FirstOrDefault - Indexed [2] Linq„œŒwi 'Linq63' [3] APL„1.7 2.3 4.1 1.9 2.9 [4] APL„(0=+/×(³¯0.5 0.5°.+(-Œio)+¼½APL)-[Œio]APL)/APL [5] :if 0=½APL [6] APL„˜/0 [7] :else [8] APL„нAPL [9] :endif [10] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The result:

Linq63 Actual Result 1 LINQ 1.797693135E308 APL 1.797693135E308 Match? 1.000000000E0

There are no elements within ±0.5 of its position in the vector.

1.10.7 ElementAt

This query returns the fourth number less that 5 in an integer vector. The sample first uses a query expression then uses ‘ElementAt’ to retrieve the fourth number from this sequence. Since ElementAt uses 0-based indexing, 3 is passed to the method to retrieve the fourth element.

Linq64 LINQ 2 APL 2 Match? 1

Page 48: Linq to Objects 101 Samples C to AplWin

Page 48 of 69

The matching result is produced by the following APL+Win function:

’ Z„Linq64;Linq;APL [1] © Element Operators: ElementAt [2] Linq„œŒwi 'Linq64' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„н3‡(APL<5)/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.11 Generation Operators

This group of queries or operators generate sequences: the samples provided generate sequences of integers. What is striking is the simplicity of the APL+Win code to generate identical results produced by the C# code.

1.11.1 Range

This query uses ‘Range’ to generate a sequence of numbers from 100 to 149 and then classifies each element of the resulting vector as either odd or even.

’ Z„Linq65;Linq;APL [1] © Generation Operators: Range [2] Linq„³œŒwi 'Linq65' [3] APL„100+(-Œio)+¼50 [4] APL„³œAPL (('even' 'odd')[Œio+2|APL]) [5] Z„•(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

For APL+Win, this group of operators are trivial or routine.

1.11.2 Repeat

In the context of APL+Win, this is another trivial example. Moreover, the APL+Win technique of replication applies equally to other types of data.

Linq66 LINQ 7 7 7 7 7 7 7 7 7 7 APL 7 7 7 7 7 7 7 7 7 7 Match? 1

The APL+Win function:

’ Linq66;Linq;APL [1] © Generation Operators: Repeat [2] Linq„Œwi 'Linq66' [3] APL„10/7 [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Page 49: Linq to Objects 101 Samples C to AplWin

Page 49 of 69

1.12 Quantifiers

This group of operators apply criteria within the elements of vectors. APL+Win does this type of processing quite naturally using standard primitives.

1.12.1 Any - Simple

This query determines whether any words in a string array contain the character sequence 'ei'; it returns 1 or true if at least one element contains the designated substring.

Linq67 LINQ 1 APL 1 Match? 1

’ Z„Linq67;Linq;APL [1] © Quantifiers: Any - Simple [2] Linq„œŒwi 'Linq67' [3] APL„"believe" "relief" "receipt" "field" [4] APL„1¹(›'ie')Ÿ.º¨APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.12.2 Any - Indexed

The code sample given at the URL is plainly wrong! This sample determines whether any numbers in an integer array are the negative of their position in the vector.

The culprit line is: bool negativeMatch = numbers.Any((n, index) => n == -index);

The correction is:

bool negativeMatch = numbers.Select((n, index) => new { n, index }).Any(x => x.n == -x.index); This is an appropriate point to pause and consider the readability of APL+Win code, comparing it to the

corresponding C# code.

Linq68 LINQ 0 APL 0 Match? 1

This function produces the matching result:

’ Z„Linq68;Linq;APL [1] © Quantifiers: Any - Indexed [2] APL„¯9 4 ¯8 3 ¯5 2 ¯1 6 ¯7 [3] Linq„Œwi 'Linq68' APL [4] APL„×½(APL=-(-Œio)+¼½APL)/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.12.3 Any - Grouped

1.12.4 All - Simple

This query uses All to determine whether an array contains only odd numbers. This type of query represents very basic APL+Win skills of novices!

Linq70 LINQ 1 APL 1

Page 50: Linq to Objects 101 Samples C to AplWin

Page 50 of 69

Match? 1

This function produces the matching result:

’ Z„Linq70;Linq;APL [1] © Quantifiers: All - Simple [2] Linq„œŒwi 'Linq70' [3] APL„1 11 3 19 41 65 19 [4] APL„1^.=2|APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.12.5 All - Indexed

The sample code given for this example is also incorrect. The following line is incorrect: bool allLower = lowNumbers.All((num, index) => num < highNumbers[index]);

It creates an error that prevents the code from compiling: System.Func<int,bool>' does not take '2' arguments

The correct line is: bool allLower = lowNumbers.Select((n, index) => new { n, index }).All(x => x.n < highNumbers[x.index]); This sample determines whether every element of an integer vector is lower than the corresponding

element in another integer vector; the two vectors are conformable.

Linq71 LINQ 1 APL 1 Match? 1

’ Z„Linq71;Linq;APL;lowNumbers;highNumbers [1] © Quantifiers: All - Indexed [2] lowNumbers„ 1 11 3 19 41 65 19 [3] highNumbers„ 7 19 42 22 45 79 24 [4] Linq„Œwi 'Linq71' lowNumbers highNumbers [5] APL„lowNumbers^.<highNumbers [6] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.12.6 All - Grouped

This query returns all of the products in categories where none of the products in that category is out of stock. The sample first uses group by to group the products into categories. It then uses Any to find those groups that have no products out of stock. Finally, the select clause creates elements of the return sequence consisting of the Category as the key and the associated group of products.

1.13 Aggregate Operators

There is a way of working with C# with the reassurance of the APL+Win comfort zone: this group of operators illustrate this admirably.

1.13.1 Count - Simple

This query returns the count of distinct elements of an integer vector.

Linq73 LINQ 3 APL 3 Match? 1

Page 51: Linq to Objects 101 Samples C to AplWin

Page 51 of 69

The APL+Win function that produces the matching result:

’ Z„Linq73;Linq;APL [1] © Aggregate Operators - Count - Simple [2] Linq„Œwi 'Linq73' [3] APL„2 2 3 5 5 [4] APL„н½((APL¼APL)=¼½APL)/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Note that the APL+Win solution needs to match the C# result: scalar for scalar, see line [4].

1.13.2 Count - Conditional

This sample finds the number of odd elements of an integer array. This describes the C# inner workings: “The sample passes a lambda expression to Count that it uses to perform the test, while Count handles the iteration and maintains the running total.”

I am finding the documentation of the solution difficult to understand, let alone the solution itself! In contrast, the APL+Win solution could not be simpler.

Linq74 LINQ 5 APL 5 Match? 1

’ Z„Linq74;Linq;APL [1] © Aggregate Operators - Count - Conditional [2] Linq„œŒwi 'Linq74' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„2+.|APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.3 Count - Indexed

The code sample provided at the URL does not compile. The culprit line is: int oddEvenMatches = numbers.Count((n, index) => n % 2 == index % 2); It causes the following error: Delegate 'System.Func<int,bool>' does not take '2' arguments

The correct line is: int oddEvenMatches = numbers.Where((n, index) => n % 2 == index % 2).Count();

Linq75 LINQ 4 APL 4 Match? 1

’ Z„Linq75;Linq;APL [1] © Aggregate Operators - Count - Indexed [2] Linq„œŒwi 'Linq75' [3] numbers„5 4 1 3 9 8 6 7 2 0 [4] APL„(2|numbers)+.^2|(-Œio)+¼½numbers © odd numbers at odd

positions (index origin zero) [5] APL„APL+(~2|numbers)+.^~2|(-Œio)+¼½numbers © even numbers at even

positions (index origin zero) [6] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Page 52: Linq to Objects 101 Samples C to AplWin

Page 52 of 69

1.13.4 Count - Nested

This sample uses Count to return a list of customers and how many orders each has; it includes customers with nil orders.

’ Z„Linq76;Linq;APL [1] © Aggregate Operators - Count - Nested [2] Linq„œŒwi 'Linq76' [3] APL„Œwi 'GetCustomerListEx' [4] CustomerID„Œioœ¨APL [5] OrderCount„¹½¨(Œio+9)œ¨APL [6] APL„³œCustomerID OrderCount [7] Z„•(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.5 Count - Grouped

This sample prints each category and the number of products in that category. The sample first uses group by to group the products according to their categories. Then it uses select to create an anonymous for each category that contains the category and number of products. Linq77 LINQ APL Match? Beverages 12 Beverages 12 1 Condiments 12 Condiments 12 Produce 5 Produce 5 Meat/Poultry 6 Meat/Poultry 6 Seafood 12 Seafood 12 Dairy Products 10 Dairy Products 10 Confections 13 Confections 13 Grains/Cereals 7 Grains/Cereals 7

’ Z„Linq77;Linq;APL;a [1] © Aggregate Operators - Count - Grouped [2] Linq„œŒwi 'Linq77' [3] APL„Œwi 'GetProductListEx' [4] Category„(Œio+2)œ¨APL [5] a„((Category¼Category)=¼½Category)/Category [6] APL„³œa (+š(a¼Category)°.=¼½a) [7] Z„•(›¨'LINQ' 'APL' 'Match?'),[Œio-0.5]Linq APL (Linq−APL) ’

1.13.6 Sum - Simple

This query uses Sum to find the total of all of the numbers in an integer array. Sounds familiar?

LINQ 45 APL 45 Match? 1

Page 53: Linq to Objects 101 Samples C to AplWin

Page 53 of 69

’ Z„Linq78;Linq;APL [1] © Aggregate Operators - Sum - Simple [2] Linq„Œwi 'Linq78' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„+/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.7 Sum - Projection

This sample uses Sum to find the total number of characters in all of the words in a string array.

Linq79 LINQ 20 APL 20 Match? 1

’ Z„Linq79;Linq;APL [1] © Aggregate Operators - Sum - Projection [2] Linq„,Œwi 'Linq79' [3] APL„"cherry" "apple" "blueberry" [4] APL„,¹+/½¨APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.8 Sum - Grouped

This query returns, for each category, the total number of units in stock for all products in that category.

Linq80 LINQ APL Match? Beverages 559 Beverages 559 1 Condiments 507 Condiments 507 Produce 100 Produce 100 Meat/Poultry 165 Meat/Poultry 165 Seafood 701 Seafood 701 Dairy Products 393 Dairy Products 393 Confections 386 Confections 386 Grains/Cereals 308 Grains/Cereals 308

’ Z„Linq80;Linq;APL [1] © Aggregate Operators - Sum - Grouped [2] Linq„œŒwi 'Linq80' [3] APL„Œwi 'GetProductListEx' [4] (Category UnitsInStock)„(Œio+2 4)œ¨¨›APL [5] DistinctCategory„((Category¼Category)=¼½Category)/Category [6]

UnitsInStock„((DistinctCategory¼Category)°.=¼½DistinctCategory)×[Œio]UnitsInStock © Separate UnitsInStock by Category (into columns)

[7] APL„³œDistinctCategory (+šUnitsInStock) [8] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.13.9 Min - Simple

This sample uses Min to get the lowest number in an integer array.

Linq81 LINQ 0 APL 0 Match? 1

’ Z„Linq81;Linq;APL [1] © Aggregate Operators - Min - Simple [2] Linq„œŒwi 'Linq81' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„˜/APL

Page 54: Linq to Objects 101 Samples C to AplWin

Page 54 of 69

[5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.10 Min - Projection

This sample uses Min to get the length of the shortest word in a string array.

Linq82 LINQ 5 APL 5 Match? 1

’ Z„Linq82;Linq;APL [1] © Aggregate Operators - Min - Projection [2] Linq„œŒwi 'Linq82' [3] APL„"cherry" "apple" "blueberry" [4] APL„н¹˜/½¨APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.11 Min - Grouped

This query finds, for each category, the lowest of all product prices.

Linq83 LINQ APL Match? Beverages 4.50 Beverages 4.50 1 Condiments 10.00 Condiments 10.00 Produce 10.00 Produce 10.00 Meat/Poultry 7.45 Meat/Poultry 7.45 Seafood 6.00 Seafood 6.00 Dairy Products 2.50 Dairy Products 2.50 Confections 9.20 Confections 9.20 Grains/Cereals 7.00 Grains/Cereals 7.00

’ Z„Linq83;Linq;APL;UnitPrice;Category;DistinctCategory [1] © Aggregate Operators - Min - Grouped [2] Linq„œŒwi 'Linq83' [3] APL„Œwi 'GetProductListEx' [4] (Category UnitPrice)„(Œio+2 3)œ¨¨›APL [5] DistinctCategory„((Category¼Category)=¼½Category)/Category [6]

UnitPrice„((DistinctCategory¼Category)°.=¼½DistinctCategory)×[Œio]UnitPrice © Separate prices by Category (into columns)

[7] ((0=,UnitPrice)/,UnitPrice)„˜/Ð [8] APL„³œDistinctCategory (˜šUnitPrice) [9] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

Pause a moment and consider this question: what is the purpose of line [7]?

1.13.12 Min - Elements

This query returns the cheapest price in each category

Page 55: Linq to Objects 101 Samples C to AplWin

Page 55 of 69

’ Z„Linq84;Linq;APL;Category;UnitPrice;DistinctCategory [1] © Aggregate Operators - Max - Grouped [2] Linq„œŒwi 'Linq84' [3] APL„Œwi 'GetProductListEx' [4] (Category UnitPrice)„(Œio+2 3)œ¨¨›APL [5] DistinctCategory„((Category¼Category)=¼½Category)/Category [6]

UnitPrice„((DistinctCategory¼Category)°.=¼½DistinctCategory)×[Œio]UnitPrice © Separate prices by Category (into columns)

[7] ((0=,UnitPrice)/,UnitPrice)„˜/Ð [8] APL„›[Œio+1](¹Ÿ/(›[Œio]UnitPrice)¹¨˜šUnitPrice)šœAPL [9] APL„œAPL[“DistinctCategory¼(Œio+2)œ¨APL] © Reorder in original category

order [10] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

The APL+Win solution has an interesting twist: refer to line [7].

1.13.13 Max - Simple

This sample uses Max to get the highest number in an integer array.

Linq85 LINQ 9 APL 9 Match? 1

’ Z„Linq85;Linq;APL [1] © Aggregate Operators - Max - Simple [2] Linq„œŒwi 'Linq85' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„—/APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.14 Max - Projection

This sample uses Max to get the length of the longest word in a string array.

Linq86 LINQ 9 APL 9 Match? 1

’ Z„Linq86;Linq;APL [1] © Aggregate Operators - Max - Projection [2] Linq„Œwi 'Linq86' [3] APL„"cherry" "apple" "blueberry" [4] APL„н¹—/½¨APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.15 Max - Grouped

This query returns the most expensive price in each category.

Linq87 LINQ APL Match? Beverages 263.50 Beverages 263.50 1 Condiments 43.90 Condiments 43.90 Produce 53.00 Produce 53.00 Meat/Poultry 123.79 Meat/Poultry 123.79 Seafood 62.50 Seafood 62.50 Dairy Products 55.00 Dairy Products 55.00 Confections 81.00 Confections 81.00 Grains/Cereals 38.00 Grains/Cereals 38.00

Page 56: Linq to Objects 101 Samples C to AplWin

Page 56 of 69

’ Z„Linq87;Linq;APL;Category;UnitPrice;DistinctCategory [1] © Aggregate Operators - Max - Grouped [2] Linq„œŒwi 'Linq87' [3] APL„Œwi 'GetProductListEx' [4] (Category UnitPrice)„(Œio+2 3)œ¨¨›APL [5] DistinctCategory„((Category¼Category)=¼½Category)/Category [6]

UnitPrice„((DistinctCategory¼Category)°.=¼½DistinctCategory)×[Œio]UnitPrice © Separate prices by Category (into columns)

[7] APL„³œDistinctCategory (—šUnitPrice) [8] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.13.16 Max - Elements

This sample finds the most expensive products in each category.

’ Z„Linq88;Linq;APL;Category;UnitPrice;DistinctCategory [1] © Aggregate Operators - Max - Elements [2] Linq„œŒwi 'Linq88' [3] APL„Œwi 'GetProductListEx' [4] (Category UnitPrice)„(Œio+2 3)œ¨¨›APL [5] DistinctCategory„((Category¼Category)=¼½Category)/Category [6]

UnitPrice„((DistinctCategory¼Category)°.=¼½DistinctCategory)×[Œio]UnitPrice © Separate prices by Category (into columns)

[7] APL„›[Œio+1](¹Ÿ/(›[Œio]UnitPrice)¹¨—šUnitPrice)šœAPL [8] APL„œAPL[“DistinctCategory¼(Œio+2)œ¨APL] © Reorder in original category

order [9] Z„('LINQ' 'APL' 'Match?'),[Œio-0.5] Linq APL (Linq−APL) ’

1.13.17 Average - Simple

This sample uses Average to get the average of all values of an integer array.

Linq89 LINQ 4.5 APL 4.5 Match? 1.0

’ Z„Linq89;Linq;APL [1] © Aggregate Operators - Average - Simple [2] Linq„œŒwi 'Linq89' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„н(+/APL)÷½APL © Result is scalar: would not match if a single

element vector [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.18 Average - Projection

This sample uses Average to get the average length of the words in the string array.

Page 57: Linq to Objects 101 Samples C to AplWin

Page 57 of 69

Linq90 LINQ 6.666666667 APL 6.666666667 Match? 1.000000000

’ Z„Linq90;Linq;APL [1] © Aggregate Operators - Average - Projection [2] Linq„Œwi 'Linq90' [3] APL„ "cherry" "apple" "blueberry" [4] APL„н(¹+/½¨APL)÷½APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.19 Average - Grouped

1.13.20 Fold - Simple

This sample finds the product of all elements of an array of doubles. The samples uses Fold to create a running product on the array, passing each element in turn to the lambda expression that performs the multiplication.

Linq92 LINQ 88.33081 APL 88.33081 Match? 1.00000

’ Z„Linq92;Linq;APL [1] © Aggregate Operators: Fold - Simple [2] Linq„Œwi 'Linq92' [3] APL„×/1.7 2.3 1.9 4.1 2.9 [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.13.21 Fold - Seed

This sample subtracts a sequence of integers from a starting value, simulating withdrawals from an account. While there is still cash left in the account, the withdrawal succeeds. The sample uses Fold to pass each withdrawal value in turn to the lambda expression that performs the subtraction.

Linq93 startBalance 37 attemptedWithdrawals 29 140 60 4 LINQ 17 APL 17 Match?

’ Z„Linq93;Linq;APL;startBalance;attemptedWithdrawals;i;R [1] © Aggregate Operators - Fold - Seed [2] startBalance„?1000 [3] attemptedWithdrawals„¹(2?5)?¨150 © With possible replication [4] Linq„œŒwi 'Linq93' startBalance attemptedWithdrawals [5] i„startBalance‰+\attemptedWithdrawals [6] APL„startBalance-+/i/attemptedWithdrawals [7] attemptedWithdrawals„(~i)/attemptedWithdrawals [8] :for R :in attemptedWithdrawals [9] :if APL>R [10] APL„APL-R [11] :endif [12] :endfor [13] Z„•œ(›¨'startBalance' 'attemptedWithdrawals' 'LINQ' 'APL'

'Match?'),¨startBalance attemptedWithdrawals Linq APL (Linq−APL) ’

The APL+Win function generates the arguments it uses and passes to C# randomly. This function is coded such that it allows for easy step-wise debugging.

Page 58: Linq to Objects 101 Samples C to AplWin

Page 58 of 69

1.14 Miscellaneous Operators

1.14.1 Concat - 1

This query merges two integer vectors into a single sequence. The sample uses ‘Concat’ to create the sequence with each array's values, one after the other.

This is quite simply ‘Catenate’ in APL+Win without the sophistication of optional axes specifications.

Linq94 LINQ 0 2 4 5 6 8 9 1 3 5 7 8 APL 0 2 4 5 6 8 9 1 3 5 7 8 Match? 1

The APL+Win function: ’ Z„Linq94;Linq;APL [1] © Miscellaneous Operators - Concat - 1 [2] Linq„Œwi 'Linq94' [3] APL„0 2 4 5 6 8 9,1 3 5 7 8 [4] Z„•(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.14.2 Concat - 2

This query returns all customer names followed by all product names. The LINQ solution is elaborate because the language operates at scalar level and needs to iterate to cope with arrays.

The APL+Win function:

’ Z„Linq95;Linq;APL [1] © Miscellaneous Operators - Concat - 2 [2] Linq„œŒwi 'Linq95' [3] © (ProductID ProductName Category UnitPrice UnitsInStock) (© CustomerID

CompanyName Address City Region PostalCode Country Phone Fax Orders[]) [4] APL„(œ(Œio+1)œ¨Œwi 'GetCustomerListEx') (œ(Œio+1)œ¨Œwi

'GetProductListEx') [5] APL„œ,[Œio]/((›¹0,—/¯1†¨½¨APL)—½¨APL)†¨APL [6] Z„•(›¨'LINQ' 'APL' 'Match?'),[Œio-0.5]Linq APL (Linq−APL) ’

This operation is simply catenation on the x axis.

1.14.3 EqualAll - 1

This query determines if two string vectors have the same elements in the same order. It uses ‘EqualAll’ to compare the two vectors, element by element. For string vectors in C#, the APL+Win equivalent is a nested vector. The corresponding structure for nested vector in C# is a jagged vector. However, the argument to this query is not a jagged (or nested) vector but simply a single dimensional array.

Linq96 LINQ 1 APL 1

Page 59: Linq to Objects 101 Samples C to AplWin

Page 59 of 69

Match? 1

The APL+Win function:

’ Z„Linq96;Linq;APL [1] © Miscellaneous Operators - EqualAll - 1 [2] Linq„œŒwi 'Linq96' [3] APL„"cherry" "apple" "blueberry" [4] APL„^/¹APL−¨APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

1.14.4 EqualAll - 2

This repeats of the previous query using arguments that will create the opposite result, that is, false. APL+Win returns a matching result.

Linq97 LINQ 0 APL 0 Match? 1

The function is:

’ Z„Linq97;Linq;APL [1] © Miscellaneous Operators - EqualAll - 2 [2] Linq„œŒwi 'Linq97' [3] APL„"cherry" "apple" "blueberry" [4] APL„^/¹APL−¨"apple" "blueberry" "cherry" [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The function Linq96Ex using the arguments used in this function will return a result that is true.

1.14.4.1 EqualAll - 2 : Extension

This query is looking to match not just the elements but also the order in which they occur. A useful extension is to be able to determine if two vectors match simply by content irrespective of the order of the individual elements. The APL+Win solution is:

’ Z„Linq97Ex;APL;APL2 [1] © Miscellaneous Operators - Element All [2] APL„"cherry" "apple" "blueberry" [3] APL2„"apple" "cherry" "blueberry" [4] Z„APL^.¹APL2 ’

Linq97Ex 1

1.15 Custom Sequence Operators

Some C# LINQ operators, like this one, are as old as APL itself. The C# solution is18

:

18 Copied from the Visual Studio 2008 project, hence the line numbers.

Page 60: Linq to Objects 101 Samples C to AplWin

Page 60 of 69

This appears deceptively simple; however, ‘Combine’ is defined as follows

19:

It is clear that C# not only uses a different jargon to describe standard, even routine, APL+Win

functionality but also offers comparative solutions that are comparatively much more complicated. Does this shed a new light on the arguments relating to APL+Win readability?

1.15.1 Combine

This query returns the dot product of two integer vectors. It uses a user-created sequence operator, Combine, to calculate the dot product, passing it a lambda function to multiply two vectors, element by element, and finally returns the sum as the result.

Linq98 LINQ 109 APL 109 Match? 1

This functionality in APL+Win is basic, going back to first generation APL; the function is defined as

follows:

’ Z„Linq98;Linq;APL [1] © Custom Sequence Operators - Combine [2] Linq„Œwi 'Linq98' [3] APL„0 2 4 5 6+.×1 3 5 7 8 [4] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) [5] © Error in public static class CustomSequenceOperators ’

1.15.1.1 C#:APL+Win comparison

Consider another example, returning iota 10 in index origin 1 and 0. The C# solution using LINQ:

public int[] Linq98Ex_IOTA(int io, int arg) { return Enumerable.Range(io, arg).ToArray(); }

19 This is defined incorrectly at the URL.

Page 61: Linq to Objects 101 Samples C to AplWin

Page 61 of 69

The APL+Win solution:

’ Z„Linq98Ex_IOTA;Linq;APL;Match [1] © Ajay Askoolum [2] Linq„(Œwi 'Linq98Ex_IOTA' 1 10)(Œwi 'Linq98Ex_IOTA' 0 10) [3] APL„(+\10/1) ((-Œio)+¼10) [4] Match„Linq−APL [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Neither solution incorporates any argument validation or error trapping in order to demonstrate the bare

minimum code to deliver a simple result. The result:

Linq98Ex_IOTA LINQ 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 APL 1 2 3 4 5 6 7 8 9 10 0 1 2 3 4 5 6 7 8 9 Match? 1

What does this say about APL+Win versus C# code maintenance and/or the rapid application

development credentials of the two languages?

1.16 Query Execution

This group of queries attempt to illustrate how a query is defined for deferred, immediate, and re-use execution.

1.16.1 Deferred

A query is coded such that its execution is deferred until data is requested from it. I am not sure that I understand the subtleties; however, it is possible to emulate the same behaviour.

’ Z„Linq99;Linq;APL [1] © Query Execution - Deferred [2] Linq„Œwi 'Linq99' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„–¨('+\(½APL)/1') ('(~Œio)+¼½APL') [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Reading from right-to-left, line [4] defines a query whose execution is deferred until it is executed.

Linq99 LINQ 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 APL 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 Match? 1

1.16.2 Immediate

The query executes immediately.

Linq100 LINQ 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10 APL 1 2 3 4 5 6 7 8 9 10 10 10 10 10 10 10 10 10 10 10 Match? 1

The APL+Win function:

’ Z„Linq100;Linq;APL [1] © Query Execution - Immediate [2] Linq„Œwi 'Linq100' [3] APL„5 4 1 3 9 8 6 7 2 0 [4] APL„(+\(½APL)/1) ((½APL)/½APL) [5] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

Page 62: Linq to Objects 101 Samples C to AplWin

Page 62 of 69

1.16.3 Query Reuse

The query is defined such that it can be re-used subsequently—within the same scope—with different arguments.

’ Z„Linq101;Linq;APL;Reuse [1] © Query Execution - Query Reuse [2] Linq„Œwi 'Linq101' [3] 0 0½Œdef '’ R„Reuse R',Œtcnl,'[1] R„(Rˆ3)/R’' [4] APL„5 4 1 3 9 8 6 7 2 0 [5] APL„(Reuse APL) (Reuse -APL) [6] Z„•œ(›¨'LINQ' 'APL' 'Match?'),¨Linq APL (Linq−APL) ’

The key concept is that the query is accessible for re-use within the same scope. The APL+Win solution

emulates this by defining the query as a local function; the results match.

Linq101 LINQ 1 3 2 0 ¯5 ¯4 ¯1 ¯3 ¯9 ¯8 ¯6 ¯7 ¯2 0 APL 1 3 2 0 ¯5 ¯4 ¯1 ¯3 ¯9 ¯8 ¯6 ¯7 ¯2 0 Match? 1

1.17 Time for 101 APL+Win samples?

The intrinsic value of the 101 samples is not that they provide re-usable code or that they teach the C # language; the value lies in the fact that they provide worked examples. As such, the samples provide a basis on which to promote familiarity with key concepts and to enhance developer confidence. Sadly, (and wrongly, in my opinion) APL has shirked this strategy for gaining wider acceptance.

One hundred and one LINQ samples delivered side by side in C# (the contemporary flagship language)

and APL+Win: I hope this bears witness to the credentials of APL+Win as a contemporary (where the Dot Net Framework dominates) development tool.

1.17.1 Some eligible topics

1.17.1.1 Example 1 - Return the sign of all elements of a numeric vector/array

-1 Negative 0 Zero 1 Positive

Null Null or Empty

1.17.1.2 Example 2 - Return the magnitude indicator of all elements of a numeric vector/array

, given a range -2 Is greater than Maximum -1 Is equal to Maximum 0 Within minimum and maximum 1 Is equal to Minimum 2 Is less than Minimum

1.17.1.3 Example 3 – Apply the percentage of increase

Salary 12,345 67,654 9,876 67,542 78,345 32,456 Band 0 8 0 9 3 1 Next consider the percentage increase applicable to salary bands, as follows: Increase (%) 4.5 3.45 5.12 1.78

Page 63: Linq to Objects 101 Samples C to AplWin

Page 63 of 69

Band 3 1 0 9 Note the complication: the percentage increase for band 8 is not specified/is missing. What is the amount

of increase in each Salary?

1.17.1.4 Example 4 – Re-calculate the diagonal elements of a numeric array

1.17.1.5 Example 5 – Return the powers of 2 of each element of a numeric vector/array

Ajay Askoolum April 2009

References

2. 101 LINQ Samples: http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx 3. 4. System Building with APL+Win, Ajay Askoolum, WileyBlackwell (7 Jul 2006), ISBN-10: 047003020

Page 64: Linq to Objects 101 Samples C to AplWin
Page 65: Linq to Objects 101 Samples C to AplWin

101 LINQ to Objects Samples: From C# to APL+Win

Ajay Askoolum

© Ajay Askoolum

Appendix A – Product & Customer Lists

The sample queries use the product and customer lists extensively; the way C# accesses these lists is shown in Appendix B, the code listing. For APL+Win, C# returns the same lists as nested arrays. The Product List

© ProductID ProductName Category UnitPrice UnitsInStock

œŒwi 'GetProductListEx' 1 Chai Beverages 18.00 39 2 Chang Beverages 19.00 17 3 Aniseed Syrup Condiments 10.00 13 4 Chef Anton's Cajun Seasoning Condiments 22.00 53 5 Chef Anton's Gumbo Mix Condiments 21.35 0 6 Grandma's Boysenberry Spread Condiments 25.00 120 7 Uncle Bob's Organic Dried Pears Produce 30.00 15 8 Northwoods Cranberry Sauce Condiments 40.00 6 9 Mishi Kobe Niku Meat/Poultry 97.00 29 10 Ikura Seafood 31.00 31 11 Queso Cabrales Dairy Products 21.00 22 12 Queso Manchego La Pastora Dairy Products 38.00 86 13 Konbu Seafood 6.00 24 14 Tofu Produce 23.25 35 15 Genen Shouyu Condiments 15.50 39 16 Pavlova Confections 17.45 29 17 Alice Mutton Meat/Poultry 39.00 0 18 Carnarvon Tigers Seafood 62.50 42 19 Teatime Chocolate Biscuits Confections 9.20 25 20 Sir Rodney's Marmalade Confections 81.00 40 21 Sir Rodney's Scones Confections 10.00 3 22 Gustaf's Knãckebr÷d Grains/Cereals 21.00 104 23 Tunnbr÷d Grains/Cereals 9.00 61 24 Guaranß Fantßstica Beverages 4.50 20 25 NuNuCa Nuÿ-Nougat-Creme Confections 14.00 76 26 Gumbãr Gummibãrchen Confections 31.23 15 27 Schoggi Schokolade Confections 43.90 49 28 R÷ssle Sauerkraut Produce 45.60 26 29 Thžringer Rostbratwurst Meat/Poultry 123.79 0 30 Nord-Ost Matjeshering Seafood 25.89 10 31 Gorgonzola Telino Dairy Products 12.50 0 32 Mascarpone Fabioli Dairy Products 32.00 9 33 Geitost Dairy Products 2.50 112 34 Sasquatch Ale Beverages 14.00 111 35 Steeleye Stout Beverages 18.00 20 36 Inlagd Sill Seafood 19.00 112 37 Gravad lax Seafood 26.00 11 38 C•te de Blaye Beverages 263.50 17 39 Chartreuse verte Beverages 18.00 69 40 Boston Crab Meat Seafood 18.40 123 41 Jack's New England Clam Chowder Seafood 9.65 85 42 Singaporean Hokkien Fried Mee Grains/Cereals 14.00 26 43 Ipoh Coffee Beverages 46.00 17 44 Gula Malacca Condiments 19.45 27 45 Rogede sild Seafood 9.50 5 46 Spegesild Seafood 12.00 95 47 Zaanse koeken Confections 9.50 36 48 Chocolade Confections 12.75 15 49 Maxilaku Confections 20.00 10 50 Valkoinen suklaa Confections 16.25 65 51 Manjimup Dried Apples Produce 53.00 20

Page 66: Linq to Objects 101 Samples C to AplWin

Page 66 of 69

52 Filo Mix Grains/Cereals 7.00 38 53 Perth Pasties Meat/Poultry 32.80 0 54 Tourti²re Meat/Poultry 7.45 21 55 P¼t´ chinois Meat/Poultry 24.00 115 56 Gnocchi di nonna Alice Grains/Cereals 38.00 21 57 Ravioli Angelo Grains/Cereals 19.50 36 58 Escargots de Bourgogne Seafood 13.25 62 59 Raclette Courdavault Dairy Products 55.00 79 60 Camembert Pierrot Dairy Products 34.00 19 61 Sirop d'´rable Condiments 28.50 113 62 Tarte au sucre Confections 49.30 17 63 Vegie-spread Condiments 43.90 24 64 Wimmers gute Semmelkn÷del Grains/Cereals 33.25 22 65 Louisiana Fiery Hot Pepper Sauce Condiments 21.05 76 66 Louisiana Hot Spiced Okra Condiments 17.00 4 67 Laughing Lumberjack Lager Beverages 14.00 52 68 Scottish Longbreads Confections 12.50 6 69 Gudbrandsdalsost Dairy Products 36.00 26 70 Outback Lager Beverages 15.00 15 71 Flotemysost Dairy Products 21.50 26 72 Mozzarella di Giovanni Dairy Products 34.80 14 73 R÷d Kaviar Seafood 15.00 101 74 Longlife Tofu Produce 10.00 4 75 Rh÷nbrãu Klosterbier Beverages 7.75 125 76 Lakkalik÷÷ri Beverages 18.00 57 77 Original Frankfurter gržne Soÿe Condiments 13.00 32

The Customer ListThe Customer ListThe Customer ListThe Customer List

The customer list is not tabular—ORDERS, its last element contains the orders for each customer and is nested. I recommend that you use XML NOTEPAD to examine its structure and content; CUSTOMERS.XML, an XML file, holds the structure.

Page 67: Linq to Objects 101 Samples C to AplWin

101 LINQ to Objects Samples: From C# to APL+Win

Ajay Askoolum

© Ajay Askoolum

Index

Aggregate Operators Linq73............................................................. 51 Linq74............................................................. 51 Linq75............................................................. 51 Linq77............................................................. 52 Linq78............................................................. 53 Linq79............................................................. 53 Linq80............................................................. 53 Linq81............................................................. 53 Linq82............................................................. 54 Linq83............................................................. 54 Linq84............................................................. 55 Linq85............................................................. 55 Linq86............................................................. 55 Linq87............................................................. 56 Linq88............................................................. 56 Linq89............................................................. 56 Linq90............................................................. 57 Linq92............................................................. 57 Linq93............................................................. 57

APL Functions LCase ............................................................. 21 LINQ ................................................................. 9 Linq1............................................................... 12 Linq10............................................................. 22 Linq100........................................................... 61 Linq101........................................................... 62 Linq11............................................................. 22 Linq12............................................................. 23 Linq13............................................................. 23 Linq14............................................................. 23 Linq15............................................................. 24 Linq16............................................................. 25 Linq17............................................................. 26 Linq18............................................................. 26 Linq19............................................................. 28 Linq2............................................................... 16 Linq20............................................................. 28 Linq21............................................................. 28 Linq22............................................................. 29 Linq23............................................................. 29 Linq24............................................................. 30 Linq25............................................................. 31 Linq26............................................................. 31 Linq27............................................................. 31 Linq28............................................................. 31 Linq29............................................................. 32 Linq3............................................................... 17 Linq30............................................................. 32 Linq31............................................................. 33 Linq32............................................................. 33 Linq33............................................................. 34 Linq34............................................................. 34 Linq35............................................................. 34 Linq36............................................................. 35 Linq37............................................................. 35 Linq38............................................................. 36

Linq39 .............................................................36 Linq4 ...............................................................18 Linq40 .............................................................37 Linq41 .............................................................37 Linq42 .............................................................37 Linq44 .............................................................38 Linq45 .............................................................39 Linq46 .............................................................39 Linq47 .............................................................40 Linq48 .............................................................40 Linq49 .............................................................40 Linq5 ...............................................................18 Linq50 .............................................................41 Linq51 .............................................................41 Linq52 .............................................................42 Linq53 .............................................................42 Linq54 .............................................................43 Linq55 .............................................................43 Linq56 .............................................................44 Linq57 .............................................................44 Linq58 .............................................................45 Linq59 .............................................................45 Linq6 ...............................................................19 Linq60 .............................................................45 Linq61 .............................................................45 Linq62 .............................................................46 Linq63 .............................................................47 Linq63Ex .........................................................47 Linq64 .............................................................48 Linq65 .............................................................48 Linq66 .............................................................48 Linq67 .............................................................49 Linq68 .............................................................49 Linq7 ...............................................................20 Linq70 .............................................................50 Linq71 .............................................................50 Linq73 .............................................................51 Linq74 .............................................................51 Linq75 .............................................................51 Linq76 .............................................................52 Linq77 .............................................................52 Linq78 .............................................................53 Linq79 .............................................................53 Linq8 ...............................................................21 Linq80 .............................................................53 Linq81 .............................................................53 Linq82 .............................................................54 Linq83 .............................................................54 Linq84 .............................................................55 Linq85 .............................................................55 Linq86 .............................................................55 Linq87 .............................................................56 Linq88 .............................................................56 Linq89 .............................................................56 Linq9 ...............................................................21 Linq90 .............................................................57 Linq92 .............................................................57

Page 68: Linq to Objects 101 Samples C to AplWin

Page 68 of 69

Linq93............................................................. 57 Linq94............................................................. 58 Linq95............................................................. 58 Linq96............................................................. 59 Linq97............................................................. 59 Linq97Ex......................................................... 59 Linq98............................................................. 60 Linq98Ex_IOTA .............................................. 61 Linq99............................................................. 61 UCase............................................................. 21

Comparable Nested Array................................ 38 Conversion Operators

Linq54............................................................. 43 Linq55............................................................. 43 Linq56............................................................. 44 Linq57............................................................. 44

Custom Sequence Operators Linq94............................................................. 58 Linq95............................................................. 58 Linq96............................................................. 59 Linq97............................................................. 59 Linq98............................................................. 60

CUSTOMERS.XML ........................................ 7, 66 Element Operators

Linq58............................................................. 45 Linq59............................................................. 45 Linq60............................................................. 45 Linq61............................................................. 45 Linq62............................................................. 46 Linq63............................................................. 47 Linq64............................................................. 48

Generation Operators Linq65............................................................. 48 Linq66............................................................. 48

Operators Aggregate ....................................................... 50 Conversion ..................................................... 43 CustomSequence ........................................... 59 Element .......................................................... 44 Generation...................................................... 48 Grouping......................................................... 36 Miscellaneous................................................. 58 Partitioning...................................................... 28 Projection........................................................ 19 Quantifiers ...................................................... 49 Restriction....................................................... 11 Set .................................................................. 39

Ordering Operators Linq28............................................................. 31 Linq29............................................................. 32 Linq30............................................................. 32 Linq31............................................................. 33 Linq32............................................................. 33 Linq33............................................................. 34 Linq34............................................................. 34 Linq35............................................................. 34 Linq36............................................................. 35 Linq37............................................................. 35

Linq38 .............................................................36 Linq39 .............................................................36 Linq40 .............................................................37 Linq41 .............................................................37 Linq42 .............................................................37 Linq44 .............................................................38 Linq45 .............................................................39

Partitioning Operators Linq20 .............................................................28 Linq21 .............................................................28 Linq22 .............................................................29 Linq23 .............................................................29 Linq24 .............................................................30 Linq25 .............................................................31 Linq26 .............................................................31 Linq27 .............................................................31

Projection Operators Linq10 .............................................................22 Linq11 .............................................................22 Linq12 .............................................................23 Linq13 .............................................................23 Linq14 .............................................................23 Linq15 .............................................................24 Linq16 .............................................................25 Linq17 .............................................................26 Linq18 .............................................................26 Linq19 .............................................................28 Linq6 ...............................................................19 Linq7 ...............................................................20 Linq8 ...............................................................21 Linq9 ...............................................................21

Quantifiers Linq67 .............................................................49 Linq68 .............................................................49 Linq70 .............................................................50 Linq71 .............................................................50 Linq76 .............................................................52

Query Execution Linq100 ...........................................................61 Linq101 ...........................................................62 Linq99 .............................................................61

Restriction Operators Linq1 ...............................................................12 Linq2 ...............................................................16 Linq3 ...............................................................17 Linq4 ...............................................................18 Linq5 ...............................................................18

Set Operators Linq46 .............................................................39 Linq47 .............................................................40 Linq48 .............................................................40 Linq49 .............................................................40 Linq50 .............................................................41 Linq51 .............................................................41 Linq52 .............................................................42 Linq53 .............................................................42

Signature ............................................................13 XML NOTEPAD ..............................................7, 66

Page 69: Linq to Objects 101 Samples C to AplWin

Page 69 of 69

Code Listings

The remaining pages contains listing of EXPLORE.CS and DATA.CS from the Visual Studio 2008 project that builds the COM DLL, LINQ.DLL, used throughout this article.