Java 9中的无限集

一套

Set是元素的集合,从而在任何给定的元件Set只出现一次。

更正式地说,集合不包含元素e1e2对,因此e1.equals(e2)

我们可以像这样在Java 9中轻松创建Set

final Set<Integer> s = Set.of(1, 2, 3);
System.out.println(s);

这可能会产生以下输出:

[2, 3, 1]

上面产生的Set是不可变的,即它不能更改,并且也是有限的,因为Set有不同数量的元素,即三个。 未指定通过元素的读取方法(例如stream()iterator()forEach() )返回元素的顺序。

无限集

无限集包含无限数量的元素。 无限集的一个示例是所有整数的集合[…,-1,0,1,2,…],其中整数不是Java Integer类的整数,而是根据整数的数学定义得出的整数,其中存在对于任何给定的整数n,始终为更大的整数n + 1。

有许多无限集,例如所有质数的集合,偶数整数的集合,斐波那契数的集合等。

由于明显的原因,我们无法预先计算和存储无限Java Set所有元素。 如果尝试,最终将耗尽内存。

我们必须问自己的一个基本问题是:对于我们拥有的Java类型,实际上是否存在无限集? 如果我们有一个Set<Byte>中有最多256个元素的Set ,这是远离无限的,同样的道理也适用于Short ,甚至Integer 。 毕竟,只有大约40亿个不同的Integer对象,如果使用位图表示成员身份,则可以将Set<Integer>装入0.5 GB。 尽管很大,但不是无限的。

但是,如果我们谈论的是LongString元素,那么至少实际上是在接近无限集。 要存储所有Long的位图,将需要许多PB内部存储空间。 真正的无限Set将是具有任意长度的字符[az]的所有可能组合的String Set

在继续之前,我想提一下,这篇文章中的代码也可以在GitHub上获得,如文章结尾处所述。

ImmutableStreamSet

为了摆脱存储Set元素的范式,我们可以创建一个ImmutableStreamSet ,仅通过其stream()方法定义Set的元素。 ImmutableStreamSet可以这样定义为FunctionalInterface

@FunctionalInterface
public interface ImmutableStreamSet<E> extends Set<E> {// This is the only method we need to implements@Overridepublic Stream<E> stream(); @Overridedefault int size() {return (int) stream().limit(Integer.MAX_VALUE).count();}@Overridedefault boolean contains(Object o) {return stream().anyMatch(e -> Objects.equals(e, o));}@Overridedefault boolean containsAll(Collection<?> c) {return (this == c) ? true : c.stream().allMatch(this::contains);}@Overridedefault boolean isEmpty() {return !stream().findAny().isPresent();}@Overridedefault <T> T[] toArray(T[] a) {return stream().collect(toList()).toArray(a);}@Overridedefault Object[] toArray() {return stream().toArray();}@Overridedefault Spliterator<E> spliterator() {return stream().spliterator();}@Overridedefault Iterator<E> iterator() {return stream().iterator();}@Overridedefault Stream<E> parallelStream() {return stream().parallel();}@Overridedefault void forEach(Consumer<? super E> action) {stream().forEach(action);}// We are immutable@Overridedefault boolean removeIf(Predicate<? super E> filter) {throw new UnsupportedOperationException();}@Overridedefault void clear() {throw new UnsupportedOperationException();}@Overridedefault boolean removeAll(Collection<?> c) {throw new UnsupportedOperationException();}@Overridedefault boolean retainAll(Collection<?> c) {throw new UnsupportedOperationException();}@Overridedefault boolean addAll(Collection<? extends E> c) {throw new UnsupportedOperationException();}@Overridedefault boolean remove(Object o) {throw new UnsupportedOperationException();}@Overridedefault boolean add(E e) {throw new UnsupportedOperationException();}static <E> ImmutableStreamSet<E> of(Supplier<Stream<E>> supplier) {// Check out GitHub to see how this Impl class is implementedreturn new ImmutableStreamSetImpl<>(supplier);}}

太棒了,现在我们只需提供像这样的流提供者就可以创建无限集:

ImmutableStreamSet<Long> setOfAllLong= LongStream.rangeClosed(Long.MIN_VALUE, Long.MAX_VALUE)::boxed;

这将创建一Set所有Long值(例如,具有2 ^ 64个元素)。 提供流提供程序时,必须确保遵守元素唯一性的Set属性。 考虑以下非法集:

final ImmutableStreamSet<Long> illegalSet = () -> Stream.of(1l, 2l, 1l);

显然,集合中发生11次两次,这使该对象违反了集合要求。

正如我们将看到的,最好创建我们正在考虑的无限集的具体类。 上面的默认实现的一个特殊问题是contains()方法可能非常慢。 阅读下一章,找出原因以及解决方法。

正长集

让我们假设我们要创建一个包含所有正长值的Set ,并且希望能够与其他Set和Object有效地使用Set 。 我们可以这样去做:

public final class PositiveLongSet implements ImmutableStreamSet<Long> {public static final PositiveLongSet INSTANCE = new PositiveLongSet();private PositiveLongSet() {}@Overridepublic Stream<Long> stream() {return LongStream.rangeClosed(1, Long.MAX_VALUE).boxed();}@Overridepublic int size() {return Integer.MAX_VALUE;}@Overridepublic boolean contains(Object o) {return SetUtil.contains(this, Long.class, other -> other > 0, o);}@Overridepublic boolean isEmpty() {return false;}@Overridepublic String toString() {return SetUtil.toString(this);}}

注意我们如何遵守方法size()中的形式要求,即使Set很大,我们也会在其中返回Integer.MAX_VALUE 。 如果Set已在今天定义,则size()可能会返回long而不是int 。 但是在90年代初,内部RAM通常小于1 GB。 我们在类中使用了两种实用程序方法:

SetUtil.toString()采用Set ,对前八个元素进行迭代,并返回这些元素的String表示形式。

SetUtil.contains()方法采用Set ,Element类型类(此处为Long.class )和一个Predicate ,如果我们Long.class比较的对象属于给定Element类型类(如果我们要比较的对象是null或其他类型,则该Set不包含该对象)。

这是SetUtil样子:

final class SetUtil {private static final int TO_STRING_MAX_ELEMENTS = 8;static <E> String toString(Set<E> set) {final List<String> first = set.stream().limit(TO_STRING_MAX_ELEMENTS + 1).map(Object::toString).collect(toList());final String endMarker = first.size() > TO_STRING_MAX_ELEMENTS ? ", ...]" : "]";return first.stream().limit(TO_STRING_MAX_ELEMENTS).collect(joining(", ", "[", endMarker));}static <E> boolean contains(final Set<E> set,final Class<E> clazz,final Predicate<E> predicate,final Object o) {if (o == null) {return false;}if (!(clazz.isAssignableFrom(o.getClass()))) {return false;}final E other = clazz.cast(o);return predicate.test(other);}}

有了类ImmutableStreamSetSetUtil我们现在可以轻松地创建其他无限集,例如PostitiveEvenLongSet (下面未显示,请PrimeLongSet编写), PrimeLongSet (包含可以用Long表示的所有素数)甚至FibonacciLongSet (包含所有fibonacci数字)可以用Long表示)。 这些类如下所示:

PrimeLongSet

public final class PrimeLongSet implements ImmutableStreamSet<Long> {public static final PrimeLongSet INSTANCE = new PrimeLongSet();private PrimeLongSet() {}private static final LongPredicate IS_PRIME =x -> LongStream.rangeClosed(2, (long) Math.sqrt(x)).allMatch(n -> x % n != 0);@Overridepublic Stream<Long> stream() {return LongStream.rangeClosed(2, Long.MAX_VALUE).filter(IS_PRIME).boxed();}@Overridepublic int size() {return Integer.MAX_VALUE; }@Overridepublic boolean contains(Object o) {return SetUtil.contains(this, Long.class, IS_PRIME::test, o);}@Overridepublic boolean isEmpty() {return false;}@Overridepublic String toString() {return SetUtil.toString(this);}}

斐波那契长集

public final class FibonacciLongSet implements ImmutableStreamSet<Long> {public static final FibonacciLongSet INSTANCE = new FibonacciLongSet();private FibonacciLongSet() {}@Overridepublic Stream<Long> stream() {return Stream.concat(Stream.of(0l),Stream.iterate(new Fibonacci(0, 1), Fibonacci::next).mapToLong(Fibonacci::getAsLong).takeWhile(fib -> fib > 0).boxed());}@Overridepublic int size() {return 92;}@Overridepublic boolean contains(Object o) {return SetUtil.contains(this,Long.class,other -> stream().anyMatch(fib -> Objects.equals(fib, other)),o);}@Overridepublic boolean isEmpty() {return false;}@Overridepublic String toString() {return SetUtil.toString(this);}private static class Fibonacci {final long beforeLast;final long last;public Fibonacci(long beforeLast, long last) {this.beforeLast = beforeLast;this.last = last;}public Fibonacci next() {return new Fibonacci(last, last + beforeLast);}public long getAsLong() {return beforeLast + last;}}}

注意当长回绕为负值时,我们如何使用Stream::takeWhile中断流。 可以说,当我们进行预计算并提供92的大小时,我们正在“作弊”,但否则size()会慢一些。

缝合全部

通过为这些类的实例提供带有静态提供程序的接口,我们可以封装我们的预定义集,并确保在JVM中只有这样的一个实例,如下所示:

public interface Sets {static Set<Long> positiveLongSet() {return PositiveLongSet.INSTANCE;}static Set<Long> positiveEvenLongSet() {return PositiveEvenLongSet.INSTANCE;}static Set<Long> primeLongSet() {return PrimeLongSet.INSTANCE;}static Set<Long> fibonacciLongSet() {return FibonacciLongSet.INSTANCE;}}

我们还可以将代码封装在Java 9模块中,通过将SetsImmutableStreamSet类暴露在项目的顶级包中,并将所有其他类放在名为“ internal”的包中(不公开),以确保仅可见SetsImmutableStreamSet类。 )。

这是我们如何module-info.java可能看起来像规定,两个外露类在com.speedment.infinite_sets在包等,并且实现类com.speedment.infinite_sets.internal

module-info.java

module com.speedment.infinite_sets {exports com.speedment.infinite_sets;
}

尝试一下

现在,我们可以通过首先声明现有模块的用法来创建另一个使用无限集的模块,如下所示:

module-info.java

module Infinite_sets_app {requires com.speedment.infinite_sets;
}

然后,我们可以访问模块的裸露部分。 这是尝试无限集的一种方法:

import static com.speedment.infinite_sets.Sets.*;
public class Main {public static void main(String[] args) {Stream.of(Set.of(1, 2, 3),positiveLongSet(),positiveEvenLongSet(),primeLongSet(),fibonacciLongSet()).forEachOrdered(System.out::println);// This actually completes fast due to identity equalitypositiveLongSet().containsAll(positiveLongSet());}}

这可能会产生以下输出:

[3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, ...]
[2, 4, 6, 8, 10, 12, 14, 16, ...]
[2, 3, 5, 7, 11, 13, 17, 19, ...]
[0, 1, 2, 3, 5, 8, 13, 21, ...]

参与GitHub

这篇文章中的源代码可以在GitHub上找到 。
游戏,设定和比赛…

翻译自: https://www.javacodegeeks.com/2018/06/infinite-sets-java.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346919.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

json文件读取之reader.onload中的定义的变量在其函数外部进行处理

采用FileReader读取json文件时,发现只能在reader.onload函数内部获取文件数据,且无法在函数外部访问其内部定义的变量,在网上查阅资料,发现也有博客提到这个问题,如下: VUE的reader.onload方法怎么把值抛出去 在reader.onload中的定义的变量如何在外部调用 … 网上其他…

【数字信号处理】基于DFT的滤波系列4之加窗(含MATLAB代码)

四、基于DFT的(理想)滤波 加窗以减少频谱泄漏 在上面的例子中,整数次谐波被用来产生理想中的示例。这意味着一个完整的整数周期适合正在使用的样本数。一个明显的问题是,如果使用非整数周期数(以及谐波)会怎样?答案是远没有那么有效。 在现实世界中,从这个意义上说,数…

结构为键值的map_在Java中增加Map值的最有效方法-只需搜索键一次

结构为键值的map这个问题可能被认为太基础了&#xff0c;但是在论坛中经常被问到。 在本文中&#xff0c;我将讨论一种仅在Map ONCE中搜索键的方法。 让我们首先来看一个例子。 假设我正在使用Map创建一个字符串频率列表&#xff0c;其中每个键是一个正在计数的String &#x…

【数字信号处理】基于DFT的滤波系列5之二维DFT滤波(含MATLAB代码)

五、二维DFT滤波 前几节介绍的用于对时间序列滤波的原理也可用于对图像的滤波,采用二维傅里叶变换技术。 下图为一幅图像的二维DFT(2D DFT)变换后的幅度值,该图像仅由一个恒定强度组成,因此它是0Hz分量——背景强度。在可视化 2D DFT 的结果时通常使用fftshift(),因此 DC…

Vaadin教程

1.简介 当您是后端开发人员时&#xff0c;您会听到人们说您无法创建内置HTML的UI页面并且无法使用CSS设置样式时所引起的痛苦。 就像成为后端开发人员一样&#xff0c;它具有已知的局限性&#xff0c;即我们可以播放和运行大型生产后端应用程序&#xff0c;但不能创建漂亮的页面…

【定时同步系列5】Farrow内插器结构原理和MATLAB实现

引言 通常我们接收到的信号是过采样的 x ( m T s ) x(mT_s) x(mT

【数字信号处理】基于DFT的滤波系列6之维纳滤波理论推导与MATLAB仿真

维纳(Wiener)滤波 引言 罗伯特维纳(Norbert Wiener)是一位对信号处理理论做出重大贡献的神童。维纳滤波是其中之一,维纳-辛钦(Wiener-Khinchin)定理是另一个表明信号的功率谱密度是其自相关函数的傅里叶变换的定理。他也是控制论的“鼻祖”。 我们将看一下维纳滤波器的一个…

jee web_您基于JEE的Web项目的结构是什么?

jee web在这篇文章中&#xff0c;我将尝试讨论基于Web的项目的各种组织结构&#xff0c;主要是使用JSF。 开始新项目时&#xff0c;首先想到的是如何组织Java包&#xff1f; 想象一下&#xff0c;您开发了一个基于Web的用户和组管理系统。 很长时间以来&#xff0c;我使用了以下…

【数字信号处理】希尔伯特变换系列1之相位处理(含MATLAB代码)

利用希尔伯特变换进行相位处理 相位的频域处理 在讨论“理想DFT滤波”时,我们注意到通常信号的相位将保持不变,这意味着不会发生由非线性相位引起的失真。然而,应该总是考虑相位响应(或者至少意识到它的存在)和幅度响应。对于所有频率,应该考虑幅度和相位。那么一个明显的…

【数字信号处理】分贝dB、dBm的概念及其日常使用中常见的错误

分贝的基本概念 首先,分贝的英文为decibel,单位为dB;其中bel表示声音计量单位(单位为Bel),并且有 1 dB ⁡ = 1 / 10 Bel ⁡ 1\operatorname{dB}=1/10\operatorname{Bel} 1dB

日期使用

时区糟透了。 特别是夏令时。 我不介意像与此行为相关的编程错误那样&#xff0c;不停移动时钟或失去一个小时的睡眠。 更糟糕的是Java的旧日期/时间API。 Java社区通过JSR 310公开承认了这一点&#xff0c;该版本取代了Java Date&#xff06;Time API&#xff0c;但是由于其复…

【数字信号处理】复数的另一种思考之平均风向测量(Python实现)

平均风向和风速测量 气象站每分钟测量一次风向。编写一个程序来指示五分钟内的平均方向。在以下几组读数上试一试:12、15、13、9、16 358、1、359、355、2 210、290、10、90、170 修改您的程序以处理风速输入以及方向。代码 import cmath from matplotlib.pylab import * tau…

开源mindmap_Java开发人员访谈的MindMap

开源mindmap多年来&#xff0c;我在许多Java开发人员的访谈中担任小组成员。 之前&#xff0c;我曾写过一篇标题为成功参加软件工程师技术面试的7大技巧的文章&#xff0c;其中涵盖了很少的一般准则。 在本文中&#xff0c;我将分享一个思维导图&#xff0c;其中包含Java开发人…

【数字信号处理】希尔伯特变换系列2之基于定向多普勒超声的胎儿心率监测(含MATLAB代码)

希尔伯特变换的应用 希尔伯特变换在许多工程应用中都有使用,此处主要介绍两种用法。 首先,它解决了多普勒超声胎儿心率监测器中出现的运动方向不明确的问题。第二,它与众所周知的解析信号联系起来了,在极坐标中,它能够找到信号的瞬时幅度和瞬时频率。 基于定向多普勒超…

轻松地与Java完全集成

这里介绍了如何编写完整的堆栈数据库Web应用程序&#xff0c;而无需使用SQL&#xff0c;HQL&#xff0c;PHP&#xff0c;ASP&#xff0c;HTML&#xff0c;CSS或Javascript&#xff0c;而是使用Vaadin的UI层和Speedment Stream ORM完全依赖Java。 是否曾经想过快速创建连接到您…

MATLAB读取结构体mat文件报错已损坏

遇到一个挺奇怪的事情&#xff0c;用MATLAB R2021a保存下来的.mat文件&#xff0c;里面是一个结构体&#xff1b;结果在MATLAB R2018b中load这个mat文件&#xff0c;提示“无法读取&#xff0c;改文件可能已损坏” 初步猜想可能是MATLAB版本的问题&#xff0c;正好虚拟机里有便…

【自适应盲均衡11】基于Volterra级数的双线性CMA盲均衡算法与MATLAB仿真(采用16QAM信号模型)

结果预览 16QAM信号的星座图: 输入信号的星座图: Volterra-CMA盲均衡算法的MSE曲线: 均衡后的星座图: 一、Volterra级数 由于多方面的原因,Volterra级数模型是非线性系统广泛采用的模型。简单起见,本文仍采用线性系统进行测试。 Volterra级数展开是由非递归级数组成…

矩形和升余弦成型下OQPSK信号的调制与解调仿真(最大功率法定时)

关注公号【逆向通信猿】更精彩!!! 仿真结果预览 OQPSK矩形和升余弦成型误码率曲线: 关于QPSK信号的仿真在之前的博客里已经 一、OQPSK调制原理 在QPSK体制中,它的相邻码元最大相位差达到180。由于这样的相位突变在频带受限的系统中会引起信号包络的很大起伏,这是不希…

java web 刷新_Java Web项目的保存和刷新

java web 刷新如何配置计算机以保存并刷新Java Web项目&#xff1f; 当您向开发人员提出此问题时&#xff0c;答案以“哦&#xff0c;好吧……”开头&#xff0c;并以某种可行的方式继续描述。 每个人都有自己的方式。 首先–为什么需要这个&#xff1f; 因为执行复制和重新启…

【数字信号处理】希尔伯特变换系列3之解析信号(含MATLAB代码)

希尔伯特变换&解析信号 你可能从未将DFT应用于复信号,因此你的数据将是实的,这样做的一个影响是DFT是对称的。在许多应用中,正频和负频分量都必须被处理——参见早期理想的DFT滤波,其中正频和负频分量都必须以相同的方式处理,以便滤波后的数据是实的(根据需要)。然而…