【问题标题】:How can I find the stop and start index for a Java vector?如何找到 Java 向量的停止和开始索引?
【发布时间】:2020-08-24 04:17:03
【问题描述】:

我有一个看起来像这样的向量:

y =

 Columns 1 through 19:

   1   1   1   1   1   1   1   1   1   1   1   1   2   2   2   2   2   2   2

 Columns 20 through 38:

   2   2   2   2   3   3   3   3   3   3   3   3   3   3   3   4   4   4   4

 Columns 39 through 57:

   4   4   4   4   4   4   4   5   5   5   5   5   5   5   5   5   5   5   6

 Columns 58 through 67:

   6   6   6   6   6   6   6   6   6   6

向量y 总是从 1 开始并被向上计数。你会看到有很多相同的数字。这是样本的类。

这里我们有1 1 1 1 1 1 1 1 1 1 1 1 = 12 个类别编号为 1 的样本。

我们有2 2 2 2 2 2 2 2 2 2 2 = 11 个类别编号为 2 的样本。

我的问题是我想为每节课找到开始和停止。例如:第 1 类始终从索引 0 开始,在本例中以索引 11 结束。

第 2 课在第 1 课结束后直接开始。

问题:

我正在使用 EJML (Effient Java Matrix Library),我打算使用这个函数:

C = A.extractMatrix(1,4,2,8) 

等于这个 MATLAB 代码:

C = A(2:4,3:8) 

但我需要从这个y 向量中找到开始和停止索引。例如,第 3 类在什么索引中停止和启动?你有什么聪明的想法吗?

当然,我可以使用 for 循环来执行此操作,但 Java 中的 for 循环非常慢,因为我将有一个非常大的 y 向量。

建议?

编辑:

这是一个建议。是不是很好,还是可以做得更好?

private void startStopIndex(SimpleMatrix y, int c, Integer[] startStop) {
    int column = y.numCols();
    startStop[0] = startStop[1] + 1; // Begin at the next class
    for(int i = startStop[0]; i < column; i++) {
        if(y.get(i) != c) {
            break;
        }else {
            startStop[1] = i;
        }
    }

}

假设我们从以下位置调用方法:

        Integer[] startStop = new Integer[2];
        for(int i = 0; i < c; i++) {
            startStopIndex(y, c, startStop);
        }

【问题讨论】:

  • 1 1 1 2 2 1 1 这样的可能吗? (多次运行相同的编号)。 1 1 3 3 4 4 4 呢? (跳过的号码)。还有3 3 3 1 1 2 2 2? (未排序)。请尽可能说明问题
  • @LuisMendo 没有。总是如 1 1 1 1 1 2 2 2 2 2 2 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 6 6 6 6 6 7 7 8 8 8 8 8 8 8 8 8
  • 我怀疑 for 循环会很慢,但是如果不循环数据就没有办法找到它。即使矩阵库具有执行此操作的函数,它也会在该函数内部循环。唯一的另一种方法是在生成或捕获数据时跟踪它发生变化的点。
  • 所以:已排序,没有跳过数字?请将其包含在问题文本中
  • 作为参考,Matlab 解决方案将是 starts = [1 find(diff(y))+1]; ends = [st(2:end)-1 numel(y)];(基于 1 的索引)

标签: java matlab matrix vector ejml


【解决方案1】:

如果您想更快地做到这一点,那么二进制搜索就是您的朋友。将它快速组合在一起,它在 O(log n) 时间内完成,而线性搜索在 O(n) 时间内完成。它非常基本,并假设您的数据看起来与您描述的非常相似。喂给它奇怪的数据,它就会坏掉。:

int[] breakPoints(int[] arr, int low, int high){
    int[] rtrn = new int[high];
    for(int i=low;i<high;i++){
        rtrn[i]=binarySearch(arr, i, 0, arr.length-1);
    }
    return rtrn;
}

int binarySearch(int[] arr, int k, int start, int end){
    int mid = (start+end)/2;
    if(mid==arr.length){
        return -1;
    }
    if(arr[mid]==k && arr[mid+1]==k+1){
        return mid+1; //or just mid if you want before breakpoint
    }
    if(arr[mid]<=k){
        return binarySearch(arr, k, mid+1, end);
    }
    return binarySearch(arr, k, start, mid-1);
}

你可以这样称呼它:

int[] data = {1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,5,5,6,6,6,6};
int[] bp = breakPoints(data,1,6);
//return 0, 3, 8, 13, 16, 18 

【讨论】:

    【解决方案2】:

    以下是在 MATLAB 中。 for 循环将遍历存储在 x1 中的每个唯一值,然后找到该值的第一次和最后一次出现。

    x = [ 1 1 1 2 2 3 3 3 3 3 4 4 4 4 5 5 5 ]
    x1 = unique(x)'
    
    for k1 = 1:length(x1)
        x1(k1,2:3) = [find(x == x1(k1,1),1,"first"), find(x == x1(k1,1),1,"last")];
    end
    

    上面的代码产生 x1 是一个 3 列矩阵

     1     1     3
     2     4     5
     3     6    10
     4    11    14
     5    15    17
    

    【讨论】:

    • 不能用 Java 编写 MATLAB 代码;)顺便说一句,干得好!
    • @DanielMårtensson,您确实使用 MATLAB 标记了您的问题,这引起了我的注意。我认为有一个高效的 Java 变体。
    • 哦!对此感到抱歉。我标记它是因为我想谈谈如何用 Java 编写这段 MATLAB 代码。
    • 不用担心。我只是读得太快了。但我确实希望有一个等效的 Java 策略。
    【解决方案3】:

    我认为这有一个名称,但我不记得它可能是什么,但你开始通过加速搜索寻找下一个边界,然后使用二分搜索。

    您知道这些数字是按升序排列的,并且可能有很多相同的数字,因此您首先检查下一个元素。但不是一次走 1 步,而是加速走 2、4、8、16 步……直到找到更大的数字。

    一旦你找到一个更大的数字,你就走得太远了,但最后一步有初始数字,所以你知道边界在最后两步之间的某个地方,然后你对边界。

    一旦您为边界提供资金,您就可以从 1、2、4、... 开始下一个边界。

    如果您希望大多数数字的出现次数大致相同,您可以保持一个移动平均计数,并使用该平均值迈出第一步,以获得一个连续的开始。

    我将留给您实际编写代码。

    【讨论】:

    • 看看我在我的问题中的建议。你怎么看?
    • @DanielMårtensson 不是你说“Java 中的for-loops 很慢”,所以你为什么建议这样做呢?
    • 是的。他们很慢,我只是在寻找......如果有比我更好的答案。
    • @DanielMårtensson 有,例如:我的回答。
    • 但这和我做的完全一样,除了加速搜索。我认为这是不可能的。
    猜你喜欢
    • 2017-01-18
    • 1970-01-01
    • 2015-05-24
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 1970-01-01
    • 1970-01-01
    • 2021-11-01
    相关资源
    最近更新 更多