我将C#的LINQ移植到Java上尝试了一下 – jLinqer

我想在Java中使用LINQ。

我创建了一个可以在Java中使用的LINQ库。它可以解决在Java8的Stream中无法很好表达的困扰,而C#的LINQ可以流畅地表达。

jLinqer

jLinqer是一个可以在Java中使用LINQ(Language INtegrated Query: 统合语言查询)的库。它还添加了一些C#中的LINQ和Java8的Stream所缺少的功能,例如selectMany,Union,Intersect,Except等。

怎么用

如果要在Gradle中使用,请注册以下内容。

'com.github.jlinqer:jlinqer:1.0.0'

如果您在Maven中使用,请注册以下pom.xml文件。


<dependency>
    <groupId>com.github.jlinqer</groupId>
    <artifactId>jlinqer</artifactId>
    <version>1.0.0</version>
</dependency>

如果您不使用Maven,并且直接使用jLinqer的jar文件,请从以下地址下载。

Maven,”jLinqer”,https://oss.sonatype.org/content/groups/public/com/github/jlinqer/jlinqer/1.0.0/jlinqer-1.0.0.jar

LINQ – jLinqer兼容矩阵

機能LINQ(C#)jLinqer(Java)Stream(Java)【基本】

抽出Wherewherefilter射影Selectselectmap並べ替え(昇順)OrderByorderBysorted並べ替え(降順)OrderByDescendingorderByDescendingn/a後続を並べ替え(昇順)ThenBythenByn/a後続を並べ替え(降順)ThenByDescendingthenByDescendingn/a平坦化して射影SelectManyselectManyflatMap【抽出系】

n件飛ばすSkipskipskip条件を満たすまで飛ばすSkipWhileskipWhilen/an件まで流すTaketakelimit条件を満たすまで流すTakeWhiletakeWhilen/a【合成系】

連結Concatconcatconcat積集合Intersectintersectn/a和集合Unionunionn/a差集合Exceptexceptn/a内部結合Joinjoinn/a外部結合GroupJoingroupJoinn/a並びを逆にするReversereversen/a2つの値を揃えて流すZipzipn/a【グループ化、集計系】

重複を無くすDistinctdistinctdistinct畳み込みAggregateaggregatereduceグループ化GroupBygroupByCollectors.groupingBy平均AverageaverageXXXCollectors.summarizingXXX件数Countcountn/a件数LongCountlongCountcount最大Maxmaxmax最小Minminmin合計SumsumXXXCollectors.summarizingXXX先頭FirstfirstfindFirst先頭FirstOrDefaultfirstOrDefaultn/a終端Lastlastn/a終端LastOrDefaultlastOrDefaultn/a1件の値を得るSinglesinglen/a1件の値を得るSingleOrDefaultsingleOrDefaultn/a空なら既定値を返すDefaultIfEmptydefaultIfEmptyn/a指定番目の要素取得ElementAtelementAtn/a指定番目の要素取得ElementAtOrDefaultelementAtOrDefaultn/a全データが条件にマッチするか?AllallallMatchいずれかのデータが条件にマッチするか?AnyanyanyMatch【生成系】

空Emptyemptyn/a範囲を生成Rangerangen/a繰り返すRepeatrepeatn/a【その他】

全要素一致SequenceEqualsequenceEqualn/aキャストCastcastn/a一致する型のみ抽出OfTypeofTypen/a

使用方法

将java.util.List 替换成 com.github.jlinqer.collections.List 并使用。

在哪里

List<Integer> list = new List<>(1, 2, 3);

List<Integer> actual = list.where(x -> x == 1 || x == 3).toList();

assertEquals(true , actual.contains(1));
assertEquals(false, actual.contains(2));
assertEquals(true , actual.contains(3));

选择 zé)

List<Person> list = new List<>(
        new Person("React"   , 1),
        new Person("Angular" , 3),
        new Person("Backbone", 5)
);

List<String> actual = list.select(x -> x.name).toList();

assertEquals("React"   , actual.get(0));
assertEquals("Angular" , actual.get(1));
assertEquals("Backbone", actual.get(2));

按照顺序摆放

List<String> list = new List<>("Backbone", "Angular", "React");

List<String> actual = list.orderBy(x -> x).toList();

assertEquals("Angular" , actual.get(0));
assertEquals("Backbone", actual.get(1));
assertEquals("React"   , actual.get(2));

按降序排序

List<String> list = new List<>("Backbone", "Angular", "React");

List<String> actual = list.orderByDescending(x -> x).toList();

assertEquals("React"   , actual.get(0));
assertEquals("Backbone", actual.get(1));
assertEquals("Angular" , actual.get(2));

然后按照

List<Person> list = new List<>(
        new Person("Angular2", 2),
        new Person("Angular1", 2),
        new Person("React"   , 1)
);

List<String> actual = list.orderBy(x -> x.age).thenBy(x -> x.name).toList();

assertEquals("React" , actual.get(0).name);
assertEquals("Angular1", actual.get(1).name);
assertEquals("Angular2"   , actual.get(2).name);

然后按降序排列

List<Person> list = new List<>(
        new Person("Angular2", 2),
        new Person("Angular1", 2),
        new Person("React"   , 1)
);

List<String> actual = list.orderBy(x -> x.age).thenByDescending(x -> x.name).toList();

assertEquals("React" , actual.get(0).name);
assertEquals("Angular2", actual.get(1).name);
assertEquals("Angular1"   , actual.get(2).name);

选多个 (Select multiple)

List<Person> list = new List<>(
        new Person("Angular", 3, new List("1.0.1", "1.0.2")),
        new Person("React"  , 1, new List("2.0.1", "2.0.2"))
);

List<String> actual = list.selectMany(x -> x.versionHistory).toList();

assertEquals("1.0.1", actual.get(0));
assertEquals("1.0.2", actual.get(1));
assertEquals("2.0.1", actual.get(2));
assertEquals("2.0.2", actual.get(3));

跳过

List<Integer> list = new List<>(1, 2, 3);

List<Integer> actual = list.skip(2).toList();

assertEquals(3, actual.get(0).intValue());

跳过当满足条件时

List<Integer> list = new List<>(1, 2, 3, 4, 5);

List<Integer> actual = list.skipWhile(x -> x <= 3).toList();

assertEquals(4, actual.get(0).intValue());
assertEquals(5, actual.get(1).intValue());

进行

List<String> list = new List<>("Backbone", "Angular", "React");

List<String> actual = list.take(2).toList();

assertEquals(2, actual.size());
assertEquals("Backbone", actual.get(0));
assertEquals("Angular" , actual.get(1));

取出符合條件的元素

List<String> list = new List<>("Backbone", "Angular", "React");

List<String> actual = list.takeWhile(x -> x.equals("Backbone") || x.equals("Angular")).toList();

assertEquals(2, actual.size());
assertEquals("Backbone", actual.get(0));
assertEquals("Angular" , actual.get(1));

连接

List<Integer> first  = new List<>(1, 2);
List<Integer> second = new List<>(2, 3);

List<Integer> actual = first.concat(second).toList();

assertEquals(1, actual.get(0).intValue());
assertEquals(2, actual.get(1).intValue());
assertEquals(2, actual.get(2).intValue());
assertEquals(3, actual.get(3).intValue());

交叉点

List<Integer> first  = new List<>(1, 2, 3);
List<Integer> second = new List<>(1, 3);

List<Integer> actual = first.intersect(second).toList();

assertEquals(1, actual.get(0).intValue());
assertEquals(3, actual.get(1).intValue());

工会

List<Integer> first = new List<>(1, 2, 3);
List<Integer> second = new List<>(0, 1, 3, 4);

List<Integer> actual = first.union(second).toList();

assertEquals(5, actual.size());
assertEquals(1, actual.get(0).intValue());
assertEquals(2, actual.get(1).intValue());
assertEquals(3, actual.get(2).intValue());
assertEquals(0, actual.get(3).intValue());
assertEquals(4, actual.get(4).intValue());

除了…以外

List<Integer> first  = new List<>(1, 2, 3);
List<Integer> second = new List<>(1, 3);

List<Integer> actual = first.except(second).toList();

assertEquals(2, actual.get(0).intValue());

加入

List<Javascript> outer = new List<>(
        new Javascript("Angular", 1),
        new Javascript("React"  , 4),
        new Javascript("ES2016" , 5)
);
List<Javascript> inner = new List<>(
        new Javascript("Angular", 2),
        new Javascript("Angular", 3),
        new Javascript("ES2016" , 6),
        new Javascript("ES7"    , 7)
);

Function<Javascript, String> outerKey = (x) -> x.name;
Function<Javascript, String> innerKey = (y) -> y.name;
BiFunction<Javascript, Javascript, Javascript> selector = (x, y) -> new Javascript(x.name, y.age);
List<Javascript> actual = outer.join(inner, outerKey, innerKey, selector).toList();

assertEquals(3, actual.size());
assertEquals("Angular", actual.get(0).name);
assertEquals("Angular", actual.get(1).name);
assertEquals("ES2016" , actual.get(2).name);
assertEquals(2, actual.get(0).age);
assertEquals(3, actual.get(1).age);
assertEquals(6, actual.get(2).age);

群组加入

List<Javascript> outer = new List<>(
        new Javascript("Angular", 1),
        new Javascript("React"  , 4),
        new Javascript("ES2016" , 5)
);
List<Javascript> inner = new List<>(
        new Javascript("Angular", 2),
        new Javascript("Angular", 3),
        new Javascript("ES2016" , 6),
        new Javascript("ES7"    , 7)
);

Function<Javascript, String> outerKey = (x) -> x.name;
Function<Javascript, String> innerKey = (y) -> y.name;
BiFunction<Javascript, IEnumerable<Javascript>, Javascript> selector = (x, y) -> new Javascript(x.name, y.select(z -> z.age));
List<Javascript> actual = outer.groupJoin(inner, outerKey, innerKey, selector).toList();

assertEquals(3, actual.size());
assertEquals("Angular", actual.get(0).name);
assertEquals("React"  , actual.get(1).name);
assertEquals("ES2016" , actual.get(2).name);
assertEquals(2, actual.get(0).ages.elementAt(0));
assertEquals(3, actual.get(0).ages.elementAt(1));
assertEquals(0, actual.get(1).ages.count());
assertEquals(6, actual.get(2).ages.elementAt(0));

逆转

List<Integer> list = new List<>(1, 2, 3);

List<Integer> actual = list.reverse().toList();

assertEquals(3, actual.get(0).intValue());
assertEquals(2, actual.get(1).intValue());
assertEquals(1, actual.get(2).intValue());

拉链

List<Integer> first = new List<>(1, 2, 3);
List<String> second = new List<>("Angular", "React", "Backbone");

List<Integer> actual = first.zip(second, (x, y) -> String.format("%s %d", x, y)).toList();

assertEquals("1 Angular" , actual.get(0));
assertEquals("2 React"   , actual.get(1));
assertEquals("3 Backbone", actual.get(2));

独特的 (dú tè de)

List<Integer> list =
        new List<>(
                1, 2, 3,
                1, 2, 3, 4
        );

List<Integer> actual = list.distinct().toList();

assertEquals(1, actual.get(0).intValue());
assertEquals(2, actual.get(1).intValue());
assertEquals(3, actual.get(2).intValue());
assertEquals(4, actual.get(3).intValue());

汇总

List<Integer> list = new List<>(1, 2, 3);

int actual = list.aggregate((sum, elem) -> sum + elem);

assertEquals(6, actual);

按照分组

List<Person> list = new List<>(
        new Person("React"   , 1),
        new Person("Angular" , 1),
        new Person("Backbone", 5)
);

Map<Integer, IEnumerable<Person>> actual = list.groupBy(x -> x.age);

assertEquals(true, actual.get(1).any(x -> x.name.equals("React")));
assertEquals(true, actual.get(1).any(x -> x.name.equals("Angular")));
assertEquals(true, actual.get(5).any(x -> x.name.equals("Backbone")));

平均

List<Long> listLong = new List<>(1l, 2l, 3l, 4l);

double actualLong = listLong.averageLong(x -> x);

assertEquals(2.5d, actualLong, 0);

计数

List<String> list = new List<>("Backbone", "Angular", "React");

long actual = list.longCount();
int actualNone = list.count(x -> x.equals("jquery"));

assertEquals(3, actual);
assertEquals(0, actualNone);

马克斯

List<Double> listDouble = new List<>(1d, 2d, 3d);

double actualDouble = listDouble.max(x -> x);

assertEquals(3d, actualDouble, 0);

迷你

List<BigDecimal> listBigDecimal = new List<>(
        new BigDecimal(1d),
        new BigDecimal(2d),
        new BigDecimal(3d)
);

BigDecimal actualBigDecimal = listBigDecimal.min(x -> x);

assertEquals(1d, actualBigDecimal.doubleValue(), 0);

以下是对原始句子的汉语同义句:

总结

List<Integer> listInt = new List<>(1, 2, 3);

int actualInt = listInt.sumInt(x -> x);

assertEquals(6, actualInt);

首先

List<String> list = new List<>("Backbone", "Angular", "React");

String actualFirst   = list.firstOrDefault();
String actualMatch   = list.firstOrDefault(x -> x.equals("Angular"));
String actualUnMatch = list.firstOrDefault(x -> x.equals("jquery"));

assertEquals("Backbone", actualFirst);
assertEquals("Angular" , actualMatch);
assertEquals(null      , actualUnMatch);

最后一个或默认

List<Integer> list = new List<>(1, 2, 3);
List<Integer> listEmpty = new List<>();

int actual = list.lastOrDefault();
Integer actualDefaultNone = listEmpty.lastOrDefault(x -> x == 0);

assertEquals(3, actual);
assertEquals(null, actualDefaultNone);

唯一的选项

List<Integer> listMany = new List<>(1, 2, 3);
List<Integer> listEmpty = new List<>();

int actualFilter = listMany.singleOrDefault(x -> x == 3);
Integer actualUnMatch = listEmpty.singleOrDefault(x -> x == 0);

assertEquals(3, actualFilter);
assertEquals(null, actualUnMatch);

默认情况下为空

List<String> listEmpty = new List<>();

List<String> actualDefault = listEmpty.defaultIfEmpty("ES7").toList();

assertEquals("ES7", actualDefault.get(0));

取出元素或默认

List<Integer> list = new List<>(1, 2, 3);

int actual = list.elementAtOrDefault(2);
Integer actualDefault = list.elementAtOrDefault(3);

assertEquals(3, actual);
assertEquals(null, actualDefault);

the students are required to wear uniforms to school.

List<String> list = new List<>("Backbone", "Angular", "React");

boolean actual = list.all(x -> x.equals("Angular") || x.equals("Backbone") || x.equals("React"));
boolean actualNotFound = list.all(x -> x.equals("Angular") || x.equals("React"));

assertEquals(true, actual);
assertEquals(false, actualNotFound);

任何

List<String> list = new List<>("Backbone", "Angular", "React");

boolean actual = list.any(x -> x.equals("Angular"));
boolean actualNotFound = list.any(x -> x.equals("jquery"));

assertEquals(true, actual);
assertEquals(false, actualNotFound);

空的 de)

List<Double> actual = IEnumerable.empty(Double.class);

assertEquals(0, actual.count());

范围

List<Integer> actual = IEnumerable.range(-2, 3);

assertEquals(-2, actual.get(0).intValue());
assertEquals(-1, actual.get(1).intValue());
assertEquals(0 , actual.get(2).intValue());

重复

List<String> actual = IEnumerable.repeat(String.class, "Law of Cycles", 10);

assertEquals(10, actual.count());
assertEquals("Law of Cycles", actual.get(9));

相等序列

List<Integer> first = new List<>(1, 2, 3);
List<Integer> secondMatch = new List<>(1, 2, 3);
List<Integer> secondUnMatchElem = new List<>(1, 2, 4);

boolean actualMatch = first.sequenceEqual(secondMatch);
boolean actualUnMatchElm = first.sequenceEqual(secondUnMatchElem);

assertEquals(true, actualMatch);
assertEquals(false, actualUnMatchElm);

演员

List<Object> list = new List<>(1, 2, 3);

List<Integer> actual = list.cast(Integer.class).toList();

assertEquals(1, actual.get(0).intValue());
assertEquals(2, actual.get(1).intValue());
assertEquals(3, actual.get(2).intValue());

类型的

List<Object> list = new List<>(1, "2", 3, "4");

List<String>  actualStr = list.ofType(String.class).toList();
List<Integer> actualInt = list.ofType(Integer.class).toList();

assertEquals("2", actualStr.get(0));
assertEquals("4", actualStr.get(1));
assertEquals(1  , actualInt.get(0).intValue());
assertEquals(3  , actualInt.get(1).intValue());

主題

有些地方无法模拟实现LINQ的标准行为。

遅延評価になっていない

toList等で評価するように変更中 (変更済:2015/06/22)

XXXorDefault

Integer,Long,Doubleのdefault値がnullとなってしまいます。C#はプリミティブ型でジェネリクスが可能なのでデフォルト値が0が返却できます

GroupBy

返り値がMap<Key, IEnumerable>となっています。C#はIGroupingです。IEnumerableのMapが必要です。(検討中)

sumXXX,averageXXX,minXXX,maxXXX

ジェネリクスでオーバーロードができないため,メソッド名に型を含ませています。Javaのジェネリクスでオーバーロードする議論はstackoverflowでしました

Listがjava.lang.Listと重複する

Listを継承して既存のListを完全に置き換えるように作っています。java.util.Listをcom.github.jlinqer.collections.Listに変更する必要があります。正統派Iterable継承版は参考文献の”javaLinq”を参照ください

ThenBy/ThenByDescendingができない

IOrderedEnumerableの実装が必要です。(検討中) (実装済:2015/06/27)

Join,GroupJoin,Zipができない

(検討中)(Zip実装済:2015/07/05)(Join実装済:2015/10/26)(GroupJoin実装済:2015/10/26)

源代码

请在GitHub上查看源代码。如果有任何功能增加或者运行障碍,请务必提交Pull Request。

关于版本问题

    • 遅延評価版(本流)

Reuben Kuhnert “javaLinq”をfolkして,Iteratorを使用してLINQの遅延評価を再現しています
https://github.com/k–kato/jLinqer

先行評価版(傍流)

Java 8 Streamを使用してLINQを再現しています
https://github.com/k–kato/jLinqer/tree/0786bb88d0788e1d1ee540af70cbad12244da9be

文献引用

    1. – 微软参考源码,”Enumerable.cs”,http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs

 

    1. – GitHub,”javaLinq”,https://github.com/sircodesalotOfTheRound/javaLinq

 

    1. – Qiita,”LINQ to Objects と Java8-Stream API の対応表”,http://qiita.com/amay077/items/9d2941283c4a5f61f302

 

    – stackoverflow,”Generic method to perform a map-reduce operation. (Java-8)”,http://stackoverflow.com/questions/30826674/generic-method-to-perform-a-map-reduce-operation-java-8
广告
将在 10 秒后关闭
bannerAds