FP大串烧:SQL,LINQ,F#以及STL(1)

看看函数型编程范式是如何将这几种看似互不相关的技术紧密联系在一起的。
注:本文中
  • 函数型编程范式主要涉及集合(列表)操作。
  • SQL主要涉及SELECT语句。
  • LINQ主要涉及LINQ to Objects,示例代码取自Visual Studio自带的C# Samples。
  • F#主要涉及list和Seq库函数。
  • STL指C++标准库,主要涉及算法部分。

Restriction(Filtering)

限制(过滤)

  • 限制(过滤)操作用于对原始集合施加某种限制,过滤掉其中不满足条件的成员,即结果集合只包含满足条件的成员。
    限制(过滤)操作在各语言中的实现方式如下表所示:

      Restriction
    SQL(SELECT) WHERE子句
    C#(LINQ) where子句或者Where扩展方法
    F#(List) List.filter函数
    C++(STL) remove, remove_copy, remove_if, remove_copy_if等算法函数
    Haskell(Prelude) filter函数
    Java8(stream) filter方法

    以下示例代码功能为:过滤掉整形集合numbers中不小于5的成员,将结果存放在lowNums集合中。
  • SQL(SELECT)TABLE(INPUT): NUMBERS FIELD DATA NUM 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 SELECT NUM INTO LOWNUMS FROM NUMBERS WHERE NUM < 5 TABLE(OUTPUT): LOWNUMS FIELD DATA NUM 4, 1, 3, 2, 0
  • C#(LINQ) int[] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; var lowNums = numbers.Where(num => num < 5); // var lowNums = from num in numbers where num < 5 select num; // lowNums = {4, 1, 3, 2, 0}
  • F#(List) let numbers = [5; 4; 1; 3; 9; 8; 6; 7; 2; 0] let lowNums = List.filter (fun num -> num < 5) numbers // lowNums = [4; 1; 3; 2; 0]
  • C++(STL) int numbers[] = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; vector<int> lowNums; remove_copy_if(numbers, numbers + 10, back_inserter(lowNums), [](int num){return !(num < 5);}); // lowNums = [5](4,1,3,2,0)
  • Haskell(Prelude) Prelude> let numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] Prelude> let lowNums = filter (\num -> num < 5) numbers Prelude> lowNums [4,1,3,2,0]
  • Java8(stream) int[] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; IntStream lowNums = Arrays.stream(numbers).filter(num -> num < 5); // lowNums = [4, 1, 3, 2, 0}]

Projection

映射

  • 映射操作用于对原始集合各成员施加某种操作,结果集合的大小与原始集合大小相同,其成员与原始集合成员存在一一对应关系。
    映射操作在各语言中的实现方式如下表所示:

      Projection
    SQL(SELECT) SELECT子句
    C#(LINQ) select子句或者Select扩展方法
    F#(List) List.map函数
    C++(STL) transform, for_each等算法函数
    Haskell(Prelude) map函数
    Java8(stream) map方法

    以下示例代码功能为:对整形集合numbers的各成员实施加一操作,将结果存放在numsPlusOne集合中。
  • SQL(SELECT) TABLE(INPUT): NUMBERS FIELD DATA NUM 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 SELECT NUM + 1 AS NUM2 INTO NUMSPLUSONE FROM NUMBERS TABLE(OUTPUT): NUMSPLUSONE FIELD DATA NUM2 6, 5, 2, 4, 10, 9, 7, 8, 3, 1
  • C#(LINQ)int[] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; var numsPlusOne = numbers.Select(num => num + 1); // var numsPlusOne = from num in numbers select num + 1; // numsPlusOne = {6, 5, 2, 4, 10, 9, 7, 8, 3, 1}
  • F#(List) let numbers = [5; 4; 1; 3; 9; 8; 6; 7; 2; 0] let numsPlusOne = List.map (fun num -> num + 1) numbers // numsPlusOne = [6; 5; 2; 4; 10; 9; 7; 8; 3; 1]
  • C++(STL) int numbers[] = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; vector<int> numsPlusOne; transform(numbers, numbers + 10, back_inserter(numsPlusOne), [](int num){return num + 1;}); // numsPlusOne = [10](6,5,2,4,10,9,7,8,3,1)
  • Haskell(Prelude) Prelude> let numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] Prelude> let numsPlusOne = map (\num -> num + 1) numbers Prelude> numsPlusOne [6,5,2,4,10,9,7,8,3,1]
  • Java8(stream) int[] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; IntStream lowNums = Arrays.stream(numbers).map(num -> num + 1); // numsPlusOne = [6, 5, 2, 4, 10, 9, 7, 8, 3, 1]

Ordering

排序

  • 排序操作用于对原始集合按某种条件进行排序,结果集合有序,其大小与原始集合大小相同。
    排序操作在各语言中的实现方式如下表所示:

      Ordering
    SQL(SELECT) ORDER BY子句
    C#(LINQ) orderby子句或者OrderBy, OrderByDecending, ThenBy, ThenByDecending等扩展方法
    F#(List) List.sort, List.sortBy等函数
    C++(STL) sort算法函数
    Haskell(Data.List) sort, sortBy等函数
    Java8(stream) sorted方法

    以下示例代码功能为:将字符串集合words从小到大排序,结果存放在sortedWords集合中。
  • SQL(SELECT) TABLE(INPUT): WORDS FIELD DATA WORD "cherry", "apple", "blueberry" SELECT WORD INTO SORTEDWORDS FROM WORDS ORDER BY WORD TABLE(OUTPUT): SORTEDWORDS FIELD DATA WORD "apple", "blueberry", "cherry"
  • C#(LINQ) string[] words = {"cherry", "apple", "blueberry"}; var sortedWords = words.OrderBy(word => word); // var sortedWords = from word in words orderby word select word; // sortedWords = {"apple", "blueberry", "cherry"}
  • F#(List) let words = ["cherry"; "apple"; "blueberry"] let sortedWords = List.sortBy (fun word -> word) words // sortedWords = ["apple"; "blueberry"; "cherry"]
  • C++(STL) string words[] = {"cherry", "apple", "blueberry"}; vector<string> sortedWords(words, words + 3); sort(sortedWords.begin(), sortedWords.end()); // sortedWords = [3]("apple","blueberry","cherry")
  • Haskell(Data.List) Prelude> let wordsList = ["cherry", "apple", "blueberry"] Prelude> :module +Data.List Prelude Data.List> let sortedWords = sort wordsList Prelude Data.List> sortedWords ["apple","blueberry","cherry"]
  • Java8(stream) String[] words = {"cherry", "apple", "blueberry"}; Stream<string> sortedWords = Arrays.stream(words).sorted(); // sortedWords = ["apple", "blueberry", "cherry"]

Grouping

分组

  • 分组操作用于对原始集合按某一基准进行分组,结果集合为二维,第一维存放索引(键值),第二维存放键值所对应的各成员。
    分组操作在各语言中的实现方式如下表所示:

      Grouping
    SQL(SELECT) GROUP BY子句
    C#(LINQ) group... by...子句或者GroupBy扩展方法
    F#(Seq) Seq.groupBy函数
    C++(STL) 无对应算法函数,由for_each算法函数间接实现
    Haskell(Prelude) 无对应函数
    How to group similar items in a list using Haskell?
    Java8(stream) groupingBy方法

    以下示例代码功能为:对整形集合numbers进行分组,分组基准为各成员除以5后得到的余数。
  • SQL(SELECT)TABLE(INPUT): NUMBERS FIELD DATA NUM 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 SELECT NUM MOD 5 AS KEY INTO NUMBERKEYS FROM NUMBERS GROUP BY NUM MOD 5 SELECT NUM MOD 5 AS KEY, NUM INTO NUMBERGROUPS FROM NUMBERS TABLE(OUTPUT): NUMBERKEYS FIELD DATA KEY 0, 4, 1, 3, 2 TABLE(OUTPUT): NUMBERGROUPS FIELD DATA KEY 0, 4, 1, 3, 4, 3, 1, 2, 2, 0 NUM 5, 4, 1, 3, 9, 8, 6, 7, 2, 0
  • C#(LINQ) int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; var numberGroups = numbers.GroupBy(num => num % 5); // var numberGroups = from num in numbers group num by num % 5; // numberGroups = { // {Key = 0, Group = {5, 0} // {Key = 4, Group = {4, 9} // {Key = 1, Group = {1, 6} // {Key = 3, Group = {3, 8} // {Key = 2, Group = {7, 2} // }
  • F#(Seq) let numbers = [5; 4; 1; 3; 9; 8; 6; 7; 2; 0] let numberGroups = Seq.groupBy (fun num -> num % 5) numbers // numberGroups = seq [(0, seq [5; 0]); (4, seq [4; 9]); (1, seq [1; 6]); (3, seq [3; 8]); (2, seq [7; 2])]
  • C++(STL) int numbers[] = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; unordered_multimap<int, int> numberGroups; for_each(numbers, numbers + 10, [&](int num){numberGroups.insert(make_pair(num % 5, num));}); // numberGroups = [10]((0, 5),(0, 0),(4, 4),(4, 9),(1, 1),(1, 6),(3, 3),(3, 8),(2, 7),(2, 2))
  • Haskell(Prelude) Prelude> let numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0] Prelude> :module +Data.Map Prelude Data.Map> let sortAndGroupBy f xs = fromAscListWith (++) [(f x, [x]) | x <- xs] Prelude Data.Map> sortAndGroupBy (`mod` 5) numbers fromList [(0,[0,5]),(1,[6,1]),(2,[2,7]),(3,[8,3]),(4,[9,4])]
  • Java8(stream) int[] numbers = {5, 4, 1, 3, 9, 8, 6, 7, 2, 0}; Map<Integer, List<integer>> numberGroups = Arrays.stream(numbers).boxed().collect(Collectors.groupingBy((Integer num) -> num % 5)); // numberGroups = [0=[5, 0], 1=[1, 6], 2=[7, 2], 3=[3, 8], 4=[4, 9]]

Quantifier(Any)

量词Any

  • 量词Any用于判断原始集合中是否存在满足某种条件的成员,结果为逻辑值真或假。
    量词Any的逻辑判断功能在各语言中的实现方式如下表所示:

      Quantifier(Any)
    SQL(SELECT) ANY函数
    C#(LINQ) Any扩展方法
    F#(List) List.exists函数
    C++(STL) any_of算法函数
    Haskell(Prelude) any函数
    Java8(stream) anyMatch方法

    以下示例代码功能为:判断字符串集合words中是否存在包含“ei”的单词。
  • SQL(SELECT)TABLE(INPUT): WORDS FIELD DATA WORD "believe", "relief", "receipt", "field" TABLE(INPUT): BOOL FIELD DATA BOOL_V -1, 0 BOOL_T "true", "false" SELECT BOOL_T AS IAFTERE INTO RESULT FROM BOOL WHERE BOOL_V = (0 <> ANY(SELECT INSTR(WORD, "EI") FROM WORDS)) TABLE(OUTPUT): RESULT FIELD DATA IAFTERE "true"
  • C#(LINQ) string[] words = {"believe", "relief", "receipt", "field"}; bool iAfterE = words.Any(w => w.Contains("ei")); // iAfterE = true
  • F#(List) let words = ["believe"; "relief"; "receipt"; "field"] let iAfterE = List.exists (fun w -> w.ToString().Contains("ei")) words // iAfterE = true
  • C++(STL) string words[] = {"believe", "relief", "receipt", "field"}; bool iAfterE = any_of(words, words + 4, [](const string& w){return w.find("ei") != -1;}); // iAfterE = true
  • Haskell(Prelude) Prelude> let wordsList = ["believe", "relief", "receipt", "field"] Prelude> :module +Data.List Prelude Data.List> let iAfterE = any (\w -> "ei" `isInfixOf` w) wordsList Prelude Data.List> iAfterE True
  • Java8(stream) string[] words = {"believe", "relief", "receipt", "field"}; boolean iAfterE = Arrays.stream(words).anyMatch(w -> w.contains("ei")); // iAfterE = true

Quantifier(All)

量词All

  • 量词All用于判断原始集合中是否所有成员均满足某种条件,结果为逻辑值真或假。
    量词All的逻辑判断功能在各语言中的实现方式如下表所示:

      Quantifier(All)
    SQL(SELECT) ALL函数
    C#(LINQ) All扩展方法
    F#(List) List.forall函数
    C++(STL) all_of, none_of等算法函数
    Haskell(Prelude) all函数
    Java8(stream) allMatch方法

    以下示例代码功能为:判断整形集合numbers是否所有成员均为奇数。
  • SQL(SELECT)TABLE(INPUT): NUMBERS FIELD DATA WORD 1, 11, 3, 19, 41, 65, 19 TABLE(INPUT): BOOL FIELD DATA BOOL_V -1, 0 BOOL_T "true", "false" SELECT BOOL_T AS ONLYODD INTO RESULT FROM BOOL WHERE BOOL_V = (1 = ALL(SELECT NUM MOD 2 FROM NUMBERS)) TABLE(OUTPUT): RESULT FIELD DATA ONLYODD "true"
  • C#(LINQ) int[] numbers = {1, 11, 3, 19, 41, 65, 19}; bool onlyOdd = numbers.All(n => n % 2 == 1); // onlyOdd = true
  • F#(List) let numbers = [1; 11; 3; 19; 41; 65; 19] let onlyOdd = List.forall (fun n -> n % 2 = 1) numbers // onlyOdd = true
  • C++(STL) int numbers[] = {1, 11, 3, 19, 41, 65, 19}; bool onlyOdd = all_of(numbers, numbers + 7, [](int n){return n % 2 == 1;}); // onlyOdd = true
  • Haskell(Prelude) Prelude> let numbers = [1, 11, 3, 19, 41, 65, 19] Prelude> let onlyOdd = all (\n -> n `mod` 2 == 1) numbers Prelude> onlyOdd True
  • Java8(stream) int[] numbers = {1, 11, 3, 19, 41, 65, 19}; boolean onlyOdd = Arrays.stream(numbers).allMatch(n -> n % 2 == 1); // onlyOdd = true

你可能感兴趣的:(sql,F#,LINQ,FP,Numbers)