【问题标题】:Filter array to one row per multiple of ten, based on difference?根据差异将数组过滤为每十的倍数一行?
【发布时间】:2015-01-14 11:15:28
【问题描述】:

我有一个数组来保存结果集中的值。我检索数组的代码大纲是:

public String[][] ref_Details() {
  int i = 0;
  String a[][] = new String[47][11];
  try
  {  
    con = getConnection();
    stmt = con.createStatement();
    String sql=" select b.LOGTIME, b.beam_current, b.beam_energy ..."; // shortened
    stmt.executeQuery(sql);
    rs = stmt.getResultSet();

    while(rs.next()) {
      for(int j=0; j<11; j++)
        a[i][j] = rs.getString(j+1);

      i++;
    }
  }
  catch( Exception e ) { ... }
  finally {
    closeConnection(stmt, rs, con);
  }
  return a;
}

得到的样本表为:

从表中可以清楚地看出,第二列 beam_current 的值接近于从 0 到 220 的每个十的整数倍:(0, 10, 20 ... 220)。我想过滤我的数据集,以便对于十的每个倍数,我只选择最接近该倍数的行。为此我:

  1. beam_current 的所有行中减去 10 并找出获得的差异:差异最小的行是我对 10 的倍数感兴趣的唯一行。T
  2. 重复第 1 步,直到从所有行中减去总共 220 行。

我的预期结果是 22 行,而不是来自示例数据的原始 47 行。例如,上面示例数据图片中编号为 21 的行将对应于值 130 的选定行。

我的问题是我没有看到预期的结果。我试过的代码是:

public int[] ref_BeamCurrent() {
  int i = 0;
  int[] arr = new int[47];
  try
  {  
    con = getConnection();
    ...
    rs = stmt.getResultSet();

    while(rs.next()) 
    { 
      for(i=0; i<arr.length; i++)
      {
        arr[i] = rs.getInt(2);
        System.out.println(arr);
        while (i < arr.length && number <= 210)
        {
          arr[i] = arr[i] - number;
          System.out.println(arr);
          number = number + 10;
          System.out.println(number);
          i = i + 1;
          // System.out.println(arr);
        }
      }
    }
  }
  catch( Exception e ) { ... }
  finally { ... }
  return arr;
}

这段代码似乎完全选择了错误的行——我做错了什么?

【问题讨论】:

  • 为什么你不能得到 10 到 220 的总和并从第二列中扣除。您可以在循环时扣除上述值的同时获得最小值
  • @AndyBrown 我更新了我的问题
  • @SRY_JAVA 我已经编辑了你的问题,试图澄清你的目标和你遇到的问题。它是否仍然准确地描述了您期望看到的内容和您遇到的问题?
  • @AndyBrown,是的,这正是我的目标,谢谢。

标签: java multidimensional-array


【解决方案1】:

我认为您应该以不同的方式考虑这一点。你想要做的是从每行的十的倍数中找到距离。

  • 最接近的十的倍数由表达式double mult = 10d * Math.round(v / 10d) 给出
  • 与十的倍数的距离由表达式double delta = Math.abs(v - mult) 给出
  • 对于mult 的任何值,您想要的行是具有最小delta 值的行。

因此,您只需对行进行一次迭代。

  1. 获取beam_value 一行并找到它是multdelta
  2. 如果该行的delta 比之前为mult 找到的任何delta 更接近,则为该mult 记录该行,否则忽略它。
  3. 重复直到没有更多的行。

另请注意,这种方法将防止单行记录超过十的倍数,这是其他方法难以防止的。

例如(我伪造了数据,因为我没有您的 SQL 查询)。输入数据:

`0.5, 12.10, 13.00, 16.01, 21.52`

给出以下正确的输出(索引 1 比索引 2 更接近 10,索引 4 比索引 3 更接近 20):

10x 行值 0 0 0.5000 10 1 12.1000 20 4 21.5200

用代码:

public static void findClosestRowsToMultiplesOfTen() {
    // fake row values
    double[] vals = new double[]{ 0.5, 12.10, 13.00, 16.01, 21.52 };

    //  get the max value, and its multiple of ten to get the number of buckets
    double max = Double.MIN_VALUE;
    for (double v : vals) max = Math.max(max, v);
    int bucketCount = 1 + (int)(max/10);

    //  initialise the buckets array to store the closest values
    double[][] buckets = new double[bucketCount][3];
    for (int i = 0; i < bucketCount; i++){
        // store the current smallest delta in the first element
        buckets[i][0] = Double.MAX_VALUE; 
        // store the current "closest" index in the second element
        buckets[i][1] = -1d;
        // store the current "closest" value in the third element
        buckets[i][2] = Double.MAX_VALUE;
    }

    //  iterate the rows
    for (int i = 0; i < vals.length; i++)
    {
        //  get the value from the row
        double v = vals[i];
        //  get the closest multiple of ten to v
        double mult = getMultipleOfTen(v);
        //  get the absolute distance of v from the multiple of ten
        double delta = Math.abs(mult - v);
        //  get the bucket index based on the value of `mult`
        int bIdx = (int)(mult / 10d);
        //    test the last known "smallest delta" for this bucket
        if (buckets[bIdx][0] > delta)
        {
            //  this is closer than the last known "smallest delta"
            buckets[bIdx][0] = delta;
            buckets[bIdx][1] = i;
            buckets[bIdx][2] = v;
        }
    }

    //   print out the result
    System.out.format("    10x row value%n");
    for (int i = 0; i < buckets.length; i++)
    {
        double[] bucket = buckets[i];
        int multipleOfTen = i * 10;
        double rowIndex = bucket[1];
        double rowValue = bucket[2];
        System.out.format("    %,2d %,4.0f %.4f%n", 
          multipleOfTen, rowIndex, rowValue);
    }
}
public static double getMultipleOfTen(double v)
{
    return 10d * Math.round(v / 10d);
}

【讨论】:

  • 我使用 sql 查询和 rs.getInt(2) 将您的 vals 值替换为原始数据时。当我打印这些值时,它会四舍五入第二列匹配 values10,20 ...直到 220 但 我不想四舍五入但想打印 beam_current 的实际值,即第二列
  • 与您的 vals 值一样,当您打印值 12.100,21.52 时,但如果我的值是 20.02,它会四舍五入到 20 30.01 它被四舍五入到 30 。**我只想打印第二列的实际值**,没有别的。
  • @SRY_JAVA rs.getInt(2) 将截断您从 sql 查询中读取的列值(例如,20.02 将被读取为 20)。你需要rs.getDouble(2)rs.getFloat(2)
  • ,你是对的。如何在实际第二列的位置显示这个检索到的列和我的显示表。即现在我必须用我检索到的新的 beam_currents 替换从 sql 查询中检索到的表的 beam_current。我使用 JSP 作为视图技术
  • @SRY_JAVA 我不确定我是否理解您的问题。评论不是为长时间讨论而设计的,因此您可能值得提出一个新问题来获得此后续问题的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 2021-08-19
  • 2014-03-04
  • 2020-05-16
  • 2022-08-11
相关资源
最近更新 更多