Java中for循环内重复项的求和

huangapple go评论97阅读模式
英文:

Java sum of repetitive items inside for loop

问题

以下是翻译好的代码部分:

public static void main(String[] args) {

    String[] matnr = new String[] { "16400", "56000", "56000", "50000", "16400" };
    String[] lfimg = new String[] { "4.000", "5.000", "6.000", "9.000", "10.56" };

    int n = matnr.length;

    int i, j;
    int count = 0;
    int count1 = 0;
    double value = 0.0;

    // 计算唯一的物料数量
    for (i = 0; i < n; ++i)
        System.out.println(i + 1 + "号隔室的物料:" + matnr[i]);

    for (i = 0; i < n; i++) {
        for (j = 0; j < i; j++)
            if (matnr[i].equals(matnr[j]))
                break;
        if (i == j) {
            count = count + 1;
        }
    }
    System.out.println("最终数量:" + count);
    String materialArray[] = new String[count];

    for (i = 0; i < n; i++) {
        for (j = 0; j < i; j++)
            if (matnr[i].equals(matnr[j]))
                break;
        if (i == j) {

            materialArray[count1] = matnr[i];
            System.out.println("物料数组:" + materialArray[count1]);
            System.out.println("之前的数量:" + count1);
            count1 = count1 + 1;
            System.out.println("之后的数量:" + count1);

        }
    }

    System.out.println("matnr长度:" + matnr.length);
    System.out.println("物料数组长度:" + materialArray.length);

    for (i = 0; i < matnr.length; i++) {
        System.out.println("物料值:" + matnr[i]);
    }

    for (j = 0; j < materialArray.length; j++) {
        System.out.println("物料数组值:" + materialArray[j]);
    }

    System.out.println("---- ******* ------------ *********** -------- ********** ------");

    for (i = 0; i < materialArray.length; i++) {
        for (j = 0; j < matnr.length; j++) {
            if (materialArray[i].equals(matnr[j])) {

                value = value + Double.parseDouble(lfimg[j]);

                System.out.println("值:" + value);

            }
        }
    }
}

希望这可以帮助你获得期望的输出。

英文:

I have two arrays :

String[] matnr = new String[] { &quot;16400&quot;, &quot;56000&quot;, &quot;56000&quot;, &quot;50000&quot;, &quot;16400&quot; };
String[] lfimg = new String[] { &quot;4.000&quot;, &quot;5.000&quot;, &quot;6.000&quot;, &quot;9.000&quot;, &quot;10.560&quot; };

I want to find sum of lfimg items having same matnr value i.e. for matnr 16400 sum output will be 14.560, for 56000 output will be 11.000 and matnr 50000 sum output will be 9.000

below block is written by me :

	public static void main(String[] args) {
String[] matnr = new String[] { &quot;16400&quot;, &quot;56000&quot;, &quot;56000&quot;, &quot;50000&quot;, &quot;16400&quot; };
String[] lfimg = new String[] { &quot;4.000&quot;, &quot;5.000&quot;, &quot;6.000&quot;, &quot;9.000&quot;, &quot;10.56&quot; };
int n = matnr.length;
int i, j, x;
int count = 0;
int count1 = 0;
double value = 0.0;
// calculate unique material count
for (i = 0; i &lt; n; ++i)
System.out.println(i + 1 + &quot;compartment material : &quot; + matnr[i]);
for (i = 0; i &lt; n; i++) {
for (j = 0; j &lt; i; j++)
if (matnr[i] == matnr[j])
break;
if (i == j) {
count = count + 1;
}
}
System.out.println(&quot;final count &gt;&gt;&quot; + count);
String materialArray[] = new String[count];
for (i = 0; i &lt; n; i++) {
for (j = 0; j &lt; i; j++)
if (matnr[i] == matnr[j])
break;
if (i == j) {
materialArray[count1] = matnr[i];
System.out.println(&quot;Material array xxxx &gt;&gt;&quot; + materialArray[count1]);
System.out.println(&quot;count1 before &gt;&gt;&quot; + count1);
count1 = count1 + 1;
System.out.println(&quot;count1 after &gt;&gt;&quot; + count1);
}
}
System.out.println(&quot;matnr.length &gt;&gt;&quot; + matnr.length);
System.out.println(&quot;materialArray.length &gt;&gt;&quot; + materialArray.length);
for (i = 0; i &lt; matnr.length; i++) {
System.out.println(&quot;111Value   &gt;&gt;&gt; &quot; + matnr[i]);
}
for (j = 0; j &lt; materialArray.length; j++) {
System.out.println(&quot;222Value &gt;&gt;&gt; &quot; + materialArray[j]);
}
System.out.println(&quot;---- ******* ------------ *********** -------- ********** ------&quot;);
for (i = 0; i &lt; materialArray.length; i++) {
for (j = 0; j &lt; matnr.length; j++) {
if (materialArray[i].contains(matnr[j])) {
value = value + Double.parseDouble(lfimg[j]);
System.out.println(&quot;Value1   &gt;&gt;&gt;  &quot; + value);
}
}
}
}

But I'm not getting desired output. It is coming as :

Value1   &gt;&gt;&gt;  4.0
Value1   &gt;&gt;&gt;  14.56
Value1   &gt;&gt;&gt;  19.560000000000002
Value1   &gt;&gt;&gt;  25.560000000000002
Value1   &gt;&gt;&gt;  34.56

Where as I want output as :

Value1   &gt;&gt;&gt;  14.560
Value1   &gt;&gt;&gt;  11.000
Value1   &gt;&gt;&gt;  9.000

Can anybody please assist in this regard.

答案1

得分: 2

  1. 在你的最终 for 循环中,你没有重置 value 变量,这就是为什么你的打印输出中会得到越来越大的数字,最终以 34.56 结尾。你想要每个 materialArray 条目对应一个值,所以在 for (i = 0; i < materialArray.length; i++) { 之后,你需要加上 value = 0

  2. 你正在使用 materialArray[i].contains(matnr[j]) - 这是在问 matnr[j] 是否是 materialArray[i] 的子字符串。很明显你想要使用 equals。这个问题不会导致程序崩溃,但仍然是一个 bug。

  3. 你的打印工具会在每个条目匹配时打印,并且在遍历完整个列表后不再打印任何内容,导致奇怪的输出。你的意图可能是在内部循环 (for (int j = 0; j < matnr.length; j++)) 完成之后再进行打印。因此,你的 sysout 语句需要向下移动两行,放在内部循环的闭合大括号之后。结合重置你的 value,然后...

Value1   >>>  14.56
Value1   >>>  11.0
Value1   >>>  9.0

另外,第二个问题是浮点数舍入误差。你基本上不应该直接使用 toString() 或其他方式直接打印浮点数或双精度值。如果这样做,你会得到像 19.560000000000002 这样奇怪的结果。

如果我用小数表示法让你写出“三分之一”的结果,你必须要进行舍入。你不能无限地写下 .3333333,对吧?计算机(特别是双精度和浮点数)也是如此,但计算机是用二进制计数的,不是十进制。所以,计算机必须要进行一定程度的舍入,然后在十进制中“呈现”它的值,这就是奇怪现象产生的地方。这种舍入引入的不准确性是无法避免的(至少对于双精度和浮点数来说),但通常这种不准确性不会影响到你数字的相关重要性。解决方案是始终在打印数字时引导库,告诉它你期望有多少位数字。因此,可以这样做:

System.out.printf("Value1   >>>   %.4f\n", value);

%.4f 告诉打印函数在小数点后最多打印 4 位数字,而 printf 不会自动换行,所以 \n 告诉它要显式地打印换行。

最后,还有代码风格的问题。使用 Java 内置的工具,如 HashMap,可以更简单(并且更高效地)完成这个任务:

public static void main(String[] args) {
String[] matnr = new String[] { "16400", "56000", "56000", "50000", "16400" };
String[] lfimg = new String[] { "4.000", "5.000", "6.000", "9.000", "10.56" };
var values = new HashMap<String, Double>();
// 将值加载到映射中。
for (int i = 0; i < matnr.length; i++) {
double z = Double.parseDouble(lfimg[i]);
values.compute(matnr[i], (m, v) -> v == null ? z : v + z); // [1]
}
// 打印它们以展示它是如何工作的
for (var e : values.entrySet()) {
System.out.printf("%s: %.4f\n", e.getKey(), e.getValue());
}
}

标记为 [1] 的关键行是:它的意思是:为当前 matnr 条目的值进行计算,如果尚未存在值(v 为 null),那么它就是对应的 lfimg 条目,如果已经存在值,则是我们之前的值加上对应的 lfimg 条目。

英文:
  1. You do not reset the value variable in your final forloop, hence why you're getting ever increasing numbers in your print, ending in 34.56. You want one value for each materialArray entry, so immediately after for (i = 0; i &lt; materialArray.length; i++) {, you'd want value = 0.
  2. You're using materialArray[i].contains(matnr[j]) - that's asking if matnr[j] is a substring of materialArray[i]. It seems rather clear you wanted equals instead. Minor nit and doesn't break here, but a bug nonetheless.
  3. Your printer tool will print every time an individual entry matches, and prints nothing after you're gone through the whole list, resulting in this weird output. Your intent, presumably, is to let the inner loop (for (int j = 0; j &lt; matnr.length; j++)) complete, and THEN you want to print. Thus, your sysout statement needs to be shifted two lines down, after the closing bracket of the inner for loop. Combine that with resetting your value and...
Value1   &gt;&gt;&gt;  14.56
Value1   &gt;&gt;&gt;  11.0
Value1   &gt;&gt;&gt;  9.0

NB: A second issue is rounding errors. You basically should never toString() or otherwise directly print a float or double value. If you do, you get wonky weirdness like 19.560000000000002.

If I ask you, using decimal notation, to write down the result of 'one third', you must round. You can't write an infinite processing of .3333333, right? Computers (specifically, doubles and floats) are no different, but computers count in binary, not decimal. So, the computer has to round a bit, and then 'render' the value it has in decimal, and this is where the weirdness comes from. The inaccuracies introduced by this rounding cannot be avoided (at least, not with doubles and floats), but usually the inaccuracies do not creep into the relevant significance of your numbers. The solution is therefore to ALWAYS guide the libraries when printing your numbers, by telling it how many digits you are expecting. So, make it:

System.out.printf(&quot;Value1   &gt;&gt;&gt;   %.4f\n&quot;, value);

The %.4f tells the printer to print with no more than 4 digits after the dot, and printf does not automatically newline, so the \n tells it to print that newline explicitly.

Finally, there's the matter of this code style. This can be done far simpler (and more efficiently) using java's built in tools, such as HashMap:

	public static void main(String[] args) {
String[] matnr = new String[] { &quot;16400&quot;, &quot;56000&quot;, &quot;56000&quot;, &quot;50000&quot;, &quot;16400&quot; };
String[] lfimg = new String[] { &quot;4.000&quot;, &quot;5.000&quot;, &quot;6.000&quot;, &quot;9.000&quot;, &quot;10.56&quot; };
var values = new HashMap&lt;String, Double&gt;();
// load values into the map.
for (int i = 0; i &lt; matnr.length; i++) {
double z = Double.parseDouble(lfimg[i]);
values.compute(matnr[i], (m, v) -&gt; v == null ? z : v + z); // [1]
}
// print them to show it works
for (var e : values.entrySet()) {
System.out.printf(&quot;%s: %.4f\n&quot;, e.getKey(), e.getValue());
}
}

The key line is the line marked [1]: It says: To compute the value for the value at the current matnr entry, if there is no existing value yet (v would be null), it's just the corresponding entry from lfimg, and if there is an existing value, it is the sum of what we had, plus the corresponding entry from lfimg.

huangapple
  • 本文由 发表于 2020年5月30日 18:52:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/62101363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定