- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
在 java 中,EnumSet 使用 long
将其包含的项目存储在位掩码/位 vector 中( RegularEnumSet
) 或 long[]
(JumboEnumSet
)。我现在遇到了一个用例,其中我有数千个域对象(我们称它们为 Node
),每个域对象都将显示一个枚举的所有项目(我们称其为 Flag
),其顺序因对象而异.
目前我将订单存储为 Guava ImmutableSet
,因为这保证保留插入顺序。但是,我用过the methods explained on this page比较 EnumSet<Flag>
中的内存使用情况, 一个 ImmutableSet<Flag>
和一个 Flag[]
.以下是 a) Flag 有 64 个枚举项和 b) 所有三个变体都包含所有 64 个项时的结果:
EnumSet: 32 bytes
ImmutableSet: 832 bytes
Array: 272 bytes
所以我的问题是:是否有一种聪明的方法可以将枚举排序打包成一个数值,以获得比数组更小的内存占用?如果它有所作为:在我的用例中,我会假设排序总是包含所有枚举项。
澄清一下:我的枚举比那个小得多,而且我现在没有任何内存问题,这种情况也不可能给我带来内存问题。只是这种低效率困扰着我,即使是在微观层面也是如此。
更新:
根据各种答案和评论的建议,我想出了这个使用字节数组的数据结构。警告:它没有实现 Set 接口(interface)(不检查唯一值)并且它不会扩展到超出一个字节可以容纳的大型枚举。此外,复杂性非常糟糕,因为必须重复查询 Enum.values() ( see here for a discussion of this problem ),但这里是:
public class EnumOrdering<E extends Enum<E>> implements Iterable<E> {
private final Class<E> type;
private final byte[] order;
public EnumOrdering(final Class<E> type, final Collection<E> order) {
this.type = type;
this.order = new byte[order.size()];
int offset = 0;
for (final E item : order) {
this.order[offset++] = (byte) item.ordinal();
}
}
@Override
public Iterator<E> iterator() {
return new AbstractIterator<E>() {
private int offset = -1;
private final E[] enumConstants = type.getEnumConstants();
@Override
protected E computeNext() {
if (offset < order.length - 1) {
return enumConstants[order[++offset]];
}
return endOfData();
}
};
}
}
内存占用为:
EnumOrdering:104
到目前为止,这是一个非常好的结果,感谢 bestsss 和 JB Nizet!
更新:我已将代码更改为仅实现 Iterable,因为其他任何东西都需要对 equals/hashCode/contains 等进行合理的实现。
最佳答案
is there a clever way to pack the enum ordering into a numeric value
是的,您可以将排序表示为数值,但要使用它您需要转换回字节/整数数组。因为有 64 个! 64 个值的可能排序,以及 64!大于 Long.MAX_VALUE
,您需要将数字存储在 BigInteger
中。我想这将是存储顺序最节省内存的方式,尽管由于必须将数字转换为数组,您在内存中获得的内容会及时丢失。
有关在数字/数组表示之间转换的算法,请参阅 this question .
这里有一个替代上面的方法,不知道它是否和那个一样有效,你必须将代码从 int
转换为 BigInteger
-based,但它应该足以给你这个想法:
/**
* Returns ith permutation of the n numbers [from, ..., to]
* (Note that n == to - from + 1).
* permutations are numbered from 0 to n!-1, if i is outside this
* range it is treated as i%n!
* @param i
* @param from
* @param n
* @return
*/
public static int[] perm(long i, int from, int to)
{
// method specification numbers permutations from 0 to n!-1.
// If you wanted them numbered from 1 to n!, uncomment this line.
// i -= 1;
int n = to - from + 1;
int[] initArr = new int[n]; // numbers [from, ..., to]
int[] finalArr = new int[n]; // permutation of numbers [from, ..., to]
// populate initial array
for (int k=0; k<n; k++)
initArr[k] = k+from;
// compute return array, element by element
for (int k=0; k<n; k++) {
int index = (int) ((i%factorial(n-k)) / factorial(n-k-1));
// find the index_th element from the initial array, and
// "remove" it by setting its value to -1
int m = convertIndex(initArr, index);
finalArr[k] = initArr[m];
initArr[m] = -1;
}
return finalArr;
}
/**
* Helper method used by perm.
* Find the index of the index_th element of arr, when values equal to -1 are skipped.
* e.g. if arr = [20, 18, -1, 19], then convertIndex(arr, 2) returns 3.
*/
private static int convertIndex(int[] arr, int index)
{
int m=-1;
while (index>=0) {
m++;
if (arr[m] != -1)
index--;
}
return m;
}
基本上,您从初始数组的自然顺序开始,然后遍历最终数组,每次都计算接下来应该放置哪些剩余元素。此版本通过将值设置为 -1 从 init 数组中“删除”元素。使用 List
或 LinkedList
可能更直观,我只是从一些旧代码中粘贴了它。
使用上述方法并将其作为main
:
public static void main(String[] args) {
int n = (int) factorial(4);
for ( int i = 0; i < n; i++ ) {
System.out.format( "%d: %s\n", i, Arrays.toString( perm(i, 1, 4 ) ) );
}
}
你得到以下输出:
0: [1, 2, 3, 4]
1: [1, 2, 4, 3]
2: [1, 3, 2, 4]
3: [1, 3, 4, 2]
4: [1, 4, 2, 3]
5: [1, 4, 3, 2]
6: [2, 1, 3, 4]
7: [2, 1, 4, 3]
8: [2, 3, 1, 4]
9: [2, 3, 4, 1]
10: [2, 4, 1, 3]
11: [2, 4, 3, 1]
12: [3, 1, 2, 4]
13: [3, 1, 4, 2]
14: [3, 2, 1, 4]
15: [3, 2, 4, 1]
16: [3, 4, 1, 2]
17: [3, 4, 2, 1]
18: [4, 1, 2, 3]
19: [4, 1, 3, 2]
20: [4, 2, 1, 3]
21: [4, 2, 3, 1]
22: [4, 3, 1, 2]
23: [4, 3, 2, 1]
Here is an executable version on ideone .
根据 BigInteger.bitLength()
判断,应该可以在不超过 37 个字节的情况下存储 64 个元素的顺序(加上使用 BigInteger
的开销)实例)。我不知道这是否值得,但这是一个很好的练习!
关于java - 在 Java 中存储枚举的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11227990/
我正在运行一个辅助角色,并检查 Azure 上托管的存储中是否存在数据。当我将连接字符串用于经典类型的存储时,我的代码可以正常工作,但是当我连接到 V2 Azure 存储时,它会抛出此异常。 “远程服
在我的应用程序的主页上,我正在进行 AJAX 调用以获取应用程序各个部分所需的大量数据。该调用如下所示: var url = "/Taxonomy/GetTaxonomyList/" $.getJSO
大家好,我正在尝试将我的商店导入我的 Vuex Route-Gard。 路由器/auth-guard.js import {store} from '../store' export default
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我的 Windows 计算机上的本地文件夹中有一些图像。我想将所有图像上传到同一容器中的同一 blob。 我知道如何使用 Azure Storage SDKs 上传单个文件BlockBlobServi
我尝试发出 GET 请求来获取我的 Azure Blob 存储帐户的帐户详细信息,但每次都显示身份验证失败。谁能判断形成的 header 或签名字符串是否正确或是否存在其他问题? 代码如下: cons
这是用于编写 JSON 的 NeutralinoJS 存储 API。是否可以更新 JSON 文件(推送数据),而不仅仅是用新的 JS 对象覆盖数据。怎么做到的??? // Javascript
我有一个并行阶段设置,想知道是否可以在嵌套阶段之前运行脚本,所以像这样: stage('E2E-PR-CYPRESS') { when { allOf {
我想从命令行而不是从GUI列出VirtualBox VM的详细信息。我对存储细节特别感兴趣。 当我在GUI中单击VM时,可以看到包括存储部分在内的详细信息: 但是到目前为止,我还没有找到通过命令行执行
我有大约 3500 个防洪设施,我想将它们表示为一个网络来确定流动路径(本质上是一个有向图)。我目前正在使用 SqlServer 和 CTE 来递归检查所有节点及其上游组件,只要上游路径没有 fork
谁能告诉我 jquery data() 在哪里存储数据以及何时删除以及如何删除? 如果我用它来存储ajax调用结果,会有性能问题吗? 例如: $("body").data("test", { myDa
有人可以建议如何为 Firebase 存储中的文件设置备份。我能够备份数据库,但不确定如何为 firebase 存储中的文件(我有图像)设置定期备份。 最佳答案 如何进行 Firebase 存储的本地
我最近开始使用 firebase 存储和 firebase 功能。现在我一直在开发从功能到存储的文件上传。 我已经让它工作了(上传完成并且文件出现在存储部分),但是,图像永远保持这样(永远在右侧加载)
我想只允许用户将文件上传到他们自己的存储桶中,最大文件大小为 1MB,仍然允许他们删除文件。我添加了以下内容: match /myusers/{userId}/{allPaths=**} { al
使用生命周期管理策略将容器的内容从冷访问层移动到存档。我正在尝试以下策略,希望它能在一天后将该容器中的所有文件移动到存档层,但事实并非如此在职的。我设置了选择标准“一天未使用后”。 这是 json 代
对于连接到 Azure 存储端点,有 http 和 https 两个选项。 第一。 https 会带来开销,可能是 5%-10%,但我不支付同一个数据中心的费用。 第二。 http 更快,但 Auth
有人可以帮我理解这一点吗?我创建了Virtual Machine in Azure running Windows Server 2012 。我注意到 Azure 自动创建了一个存储帐户。当我进入该存
我是一名优秀的程序员,十分优秀!