这个for / in循环如何正常工作?

时间:2015-09-26 16:09:44

标签: javascript arrays loops for-loop

我正在做初学者练习,找到一组数字的均值/中位数/模式/范围。我现在正处于该模式,并找到this

var store = ['1','2','2','3','4'];
var frequency = {};  // array of frequency.
var max = 0;  // holds the max frequency.
var result;   // holds the max frequency element.
for(var v in store) {
        frequency[store[v]]=(frequency[store[v]] || 0)+1; // increment frequency.
        if(frequency[store[v]] > max) { // is this frequency > max so far ?
                max = frequency[store[v]];  // update max.
                result = store[v];          // update result.
        }
}

它有效,但我不明白。

  • 第一行|| 0做了什么?
  • 为什么我无法更改密钥名称?

frequency["key"+store[v]]=(frequency[store[v]] || 0)+1;返回{key1: 1, key2: 1, key3: 1, key4: 1}而不是{1: 1, 2: 2, 3: 1, 4: 1},因此密钥正在发挥重要作用。

  • if语句是否同时测试了密钥和值?

使用在循环内部或外部创建的变量(frequency[store[v]];)替换var freqTest = frequency[store[v]];的任何实例会破坏某些内容。

整件事情真的让我头疼。

6 个答案:

答案 0 :(得分:2)

  

什么是|| 0在第一行做什么?

当查找失败时(当还没有具有该名称的.ForeignKey(new string[] { "BlogId" })属性时)将0作为默认值,以便使用frequency s初始化地图第一次出现值,而不是1(来自NaN)。

作业可以(和初学者一样)扩展到

undefined + 1
  

为什么我不能更改密钥名称?

你可以,你必须在任何地方都这样做。

代码应该写得更加清晰:

if (frequency[key]) // the property already exists, does not give `0` or `undefined`
    frequency[key] = frequency[key] + 1;
else // the property didn't exist and the access yielded `undefined`
    frequency[key] = 1; // 0 + 1
  

if语句是否同时测试了键和值?

测试?嗯,不。它确实使用var store = ['1','2','2','3','4']; var frequency = {}; // object (key-value-map) of frequency var max = 0; // holds the max frequency value var result; // holds the max frequency element name for (var v=0; v<store.length; v++) { var key = "key" + store[v]; frequency[key] = (frequency[key] || 0)+1; // increment frequency // ^^^ here as well if (frequency[key] > max) { // is this frequency > max so far ? max = frequency[key]; // update max. result = store[v]; // update result. // ^^^^^^^^ alternatively use `key` also here } } 数组中的值作为store对象中的键。然后它会将属性值与frequency进行比较。

答案 1 :(得分:2)

整个逻辑中的关键是理解这一行

import Foundation

class WastesGainsClass {
    var value: Int

    init(value: Int) {
        self.value = value
    }
}

extension WastesGainsClass {
    convenience init(dict: [NSObject: AnyObject]) {
        self.init(value: dict["value"] as? Int ?? 0)
    }

    func toDict() -> [NSObject: AnyObject] {
        var d = [NSObject: AnyObject]()
        d["value"] = value
        return d
    }
}

var gains = [WastesGainsClass(value: 1), WastesGainsClass(value: 2)]

NSUserDefaults.standardUserDefaults().setObject(gains.map { $0.toDict() }, forKey: "gains")

if let dicts = NSUserDefaults.standardUserDefaults().objectForKey("gains") as? [[NSObject: AnyObject]] {
    gains = dicts.map { WastesGainsClass(dict: $0) }
}

左侧用作某个数字的地图。当v等于3 store [3]返回2时,访问频率[2]。

现在对于相同的迭代考虑右侧。我们已经知道了

frequency[store[v]]=(frequency[store[v]] || 0)+1;

解析为

frequency[store[3]] 

但是这会带来什么回报呢?由于频率[2]也将在迭代2中设置,我们将从迭代2中访问该数字。现在让我们看一下从迭代2得到的值:

frequency[2]

啊......所以迭代3的值实际上是

frequency[store[2]] = (frequency[store[2]] || 0)+1
frequency[2] = (frequency[2] || 0)+1
frequency[2] = (null || 0)+1
frequency[2] = 1

如您所见,循环使用frequency [n]作为地图,并在每次找到时递增值。然后,如果值更高,则将值存储在max中。这是一种非常智能的方法来查找最高重复值,同时只迭代列表一次。

答案 2 :(得分:0)

a || 0表示如果a未定义,则取0,否则为0

您可以更改密钥名称。

var store = ['1','2','2','3', '1', '1','4'];
var frequency = {};  // array of frequency.
var max = 0;  // holds the max frequency.
var result;   // holds the max frequency element.
for(var v in store) {
    frequency['key'+store[v]]=(frequency['key'+store[v]] || 0)+1; // increment frequency.
    if(frequency['key' + store[v]] > max) { // is this frequency > max so far ?
            max = frequency[store[v]];  // update max.
            result = 'key' + store[v];          // update result.
    }
}

答案 3 :(得分:0)

您询问frequency[store[v]]=(frequency[store[v]] || 0)+1的行有时会被称为OR赋值;这个stack overflow question有一些很好的解释和例子。对于您的代码,请考虑我刚刚输入浏览器的javascript控制台:

> var frequency = {};
<- undefined
> frequency[0];
<- undefined
> frequency[0] || 0
<- 0

至于你为什么不能更改密钥名称,你可以,你只是没有足够的改变它们&#39;。更改正文以使用"key"+store替换每个键引用会使代码处于相同的运行状态。

for(var v in store) {
    // Increment the frequency of the value v
    frequency["key"+store[v]]=(frequency["key"+store[v]] || 0)+1; 
    // is this frequency > max so far ?
    if(frequency["key"+store[v]] > max) {
        // If it is, we have a new, most frequently occurring number
        // Update the max to this new highest frequency
        max = frequency["key"+store[v]];
        // Update the result to the new most frequent value
        result = store[v];
    }
}

我在代码中添加了一些额外的注释,以便更清楚地了解它们。

答案 4 :(得分:0)

关于你的第一个问题: 在JavaScript中,您可以测试变量是否通过将它们用作布尔值来定义。

var foo;
if(foo) //true
    console.log('foo is false, 0, null or not defined');

因此,在这种情况下,您正在测试frequency是否已有store[v]的元素。如果是,请使用它,否则请使用0,以便与

相同
var valueInFrequency = frequency[store[v]] ? frequency[store[v]] : 0;

然后继续valueInFrequency

关于你的第二个问题:正如我刚才解释的那样,

frequency[store[v]]=(frequency[store[v]] || 0)+1;

要么将当前值提高1,要么将其设置为0,然后将其提高1。如果更改键,则将值设置为但不测试新值,最后只需将现有值覆盖为0 + 1.

现在回答您的上一个问题:不,不是。它使用store[v]作为frequency的键,然后将该值与最大值

进行比较

我希望我能回答你的问题。如果还有什么不清楚,请问!

答案 5 :(得分:0)

作为给定的解决方案,我建议更好地解决这个问题。

重点放在Array.prototype.forEach的解决方案以及如果在更多项目中共享最大计数而获得多个密钥的问题。

  

发生了什么变化:

     
      
  • result现在是一个数组,因为分发的最大数量可能会影响多个键/项。
  •   
  • for ()循环由Array.prototype.forEach替换,并且回调允许以更紧凑的方式迭代数组的所有元素。
  •   
  • 只有max存储在回调中。
  •   
  • 对于具有最大计数的键/项是必要的另一个循环。
  •   
  • 首先使用Object.keys
  • 从对象获取密钥   
  • 然后迭代键并检查count === max并按下键
  •   
  • 显示所有找到的值。
  •   

关于x = x || y的含义: 如果x的值是假的(例如undefinednull0-0''),则使用y的值,因为Logical Or运营商。

var store = ['1', '2', '2', '3', '4', '5', '5'],
    distribution = {},
    max = 0,
    result = [];

store.forEach(function (a) {
    distribution[a] = (distribution[a] || 0) + 1;
    if (distribution[a] > max) {
        max = distribution[a];                
    }
});
Object.keys(distribution).forEach(function (k) {
    distribution[k] === max && result.push(k);
});
document.write('max: ' + max + '<br>');
document.write('key/s with max count: ' + JSON.stringify(result) + '<br>');
document.write('<pre>' + JSON.stringify(distribution, 0, 4) + '</pre>');