iT邦幫忙

0

javascript for/in與for遞增使用差異

下列的函式
若把

for(var i in nums)

改成

for(var i = 0; i < nums.length; i++)

會無法傳回正確的值
想請問其間差異,謝謝

/**
 * @param {number[]} nums
 * @param {number} k
 * @return {boolean}
 */
var containsNearbyDuplicate = function(nums, k) {
    var map = {};
    for(var i in nums) {
        var v = nums[i];
        if(map[v] && (i - map[v] <= k)) {
            return true;
        }
        map[v] = i;
    }
    return false;
};
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 個回答

0
小魚
iT邦大師 1 級 ‧ 2017-08-26 21:06:37

一般很多語言用的都是foreach,
意思是一樣的

for(var i = 0; i < nums.length; i++)

只能讀取連續的資料,而且不能遇到不存在的索引,否則會出錯。

foreach(var data in nums)

可以讀取不連續的資料,會將nums這個List裡面的所有資料都跑一遍,
不過foreach缺點是你不知道i是多少,
不過有些語言也有能夠讀取到key值的方式,
很多情況下是兩種方法都可以使用,
就看你的需求跟個人的習慣了。

看更多先前的回應...收起先前的回應...
小魚 iT邦大師 1 級 ‧ 2017-08-26 21:10:15 檢舉

我剛才又看了一次題目,

for(var i in nums)

裡面的i是nums這個List裡面的值

for(var i = 0; i < nums.length; i++)

是從0開始的數字,
如果你直接拿這個i下去使用,一定是會出錯的,
你試著改成

for(var i = 0; i < nums.length; i++){
var v = nums[nums[i]];
... ...

把裡面的i改成nums[i]試試看

Rafiki iT邦新手 5 級 ‧ 2017-08-26 21:15:55 檢舉

謝謝你的回答
不過我主要的問題都是for迴圈
只是他主要是for連續跟for/in這2種
因為我有自己用這兩種方法跑過其他的
感覺大致上差異不大
但不知道為什麼這邊會造成差異

Rafiki iT邦新手 5 級 ‧ 2017-08-26 21:37:24 檢舉

for/in應該是這樣吧0.0
for(變項 in 物件/陣列)
變項為物件屬性或陣列的索引

小魚 iT邦大師 1 級 ‧ 2017-08-26 23:49:19 檢舉

JavaScript的for/in我比較不熟,用C#來說明吧
假如有一個

List<int> list = new List<int> { 2, 3, 4, 5, 1 }

如果你是

for(int i=0;i<5;i++)

抓出來的i是0, 1, 2, 3, 4
但如果是

foreach(var i in list)

抓出來的i是 2, 3, 4, 5, 1

你會抓到結果不一樣可能是這個原因吧。

froce iT邦大師 1 級 ‧ 2017-08-27 02:03:11 檢舉

https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Statements/for...in
https://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-a-bad-idea
javascript 的陣列用 for in 存取和用 for 使用 index 存取的確不一樣,要注意。
for in 會跳過 array 中 undefined 的物件。

另外 array 還有個 foreach 方法。
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

Rafiki iT邦新手 5 級 ‧ 2017-08-27 11:59:32 檢舉

上網查過之後建議會用for遞增比較安全
但這邊反而是要用for/in才會回正確的值
讓我感到困惑
所以想知道差異
以更了解使用時機

小魚 iT邦大師 1 級 ‧ 2017-08-27 12:33:03 檢舉

我上面寫的你有看懂嗎?
你把你的for遞增怎麼寫的PO出來,
跟for/in比較看看,
再來討論吧。

Rafiki iT邦新手 5 級 ‧ 2017-08-27 12:41:53 檢舉
var nums = [1,3,3,1,4]
map = {};
for(var i in nums){
        var v = nums[i];
        map[v] = i;
    }
"4"
map
{1: "3", 3: "2", 4: "4"}
for(var i = 0; i < nums.length; i++){
        var v = nums[i];
        map[v] = i;
    }
4
map
{1: 3, 3: 2, 4: 4}

剛剛用console跑出的結果
關鍵差異應該就是
一個是取索引鍵
一個是取索引值
這樣我大概知道為什麼for遞增會錯了
謝謝大家的回應

froce iT邦大師 1 級 ‧ 2017-08-27 13:20:48 檢舉

...這應該是很基本的scence吧。

小魚 iT邦大師 1 級 ‧ 2017-08-27 13:21:54 檢舉

剛剛試了一下,
我誤會了,
我以為for/in 和 foreach是一樣的,
結果完全不一樣...
的確兩個i的值看起來一樣,
但不知為何一個有""一個沒有,
這你就要去找資料看看了...

Rafiki iT邦新手 5 級 ‧ 2017-08-27 14:48:13 檢舉

他判斷map裡是否已經有該屬性
if(map[v])
這個方法不夠嚴謹
這樣會變成是用map[v]的值去找屬性
所以沒有""會找不到
我覺得這邊算是碰巧有相同屬性
如果改成
if(("" + v) in map)
這樣才是確實是找屬性
改成這樣用for遞增就不會回傳錯誤
也是比較正確的作法
當初糾結的點
其實就是在於他寫法不夠嚴謹又剛好會造成差異

froce iT邦大師 1 級 ‧ 2017-08-27 22:48:50 檢舉

上面我給你的連結有寫到。
for in 會跳過陣列裡值為 undefined 的 index,所以考慮到 num = [1,3, ,3]這種情形,可以很輕易的略過 num[2] 為 undefined 不能當鍵值的問題,你用 for(i, i < num.length, i++)去做,這種處理會麻煩很多。

froce iT邦大師 1 級 ‧ 2017-08-27 22:57:16 檢舉

另外還要注意的一點,for in 取出來的值會是 string,for(i, i < num.length, i++)取出來的i會是整數。

stackoverflow那篇為什麼會說最好還是用for(i, i < num.length, i++)去做整個陣列的存取,是因為這樣能確保陣列裡每一個index都能依順序去處理,for in只會去處理有賦值的陣列元素,而且for in的順序還會依 javascript 引擎實做不同而不同,甚至結果也不同,連用prototype都會傳回prototype程式碼內容的string,所以for in不好控制。但在你給的原code我不覺得有用錯的地方。

froce iT邦大師 1 級 ‧ 2017-08-28 00:49:52 檢舉

最後 "" + v 這種寫法不能說錯,不過就閱讀上來說很難看。
建議用string(v)。

Rafiki iT邦新手 5 級 ‧ 2017-08-28 10:51:49 檢舉

謝謝/images/emoticon/emoticon12.gif

我要發表回答

立即登入回答