簡體   English   中英

Object 在 For 循環/For Each 循環中推入數組導致重復

[英]Object Push into Array within For Loop/For Each Loop is causing duplicates

我想給我的數組中的每個 object 一個與 ID 對應的屬性。 我已經嘗試了所有可能的方式,下面是最新的。

當我單獨控制台記錄 output 時,一切看起來都不錯。 但是,當我運行 output.push() 然后記錄 output 時,會出現重復項。

我發現下面的帖子看起來非常相似,但在應用建議的更改后,我仍然面臨同樣的問題——我在最終的 output 中看到重復的 ID。 IndexID 屬性不是唯一的,它應該適用於每次迭代。

反應 object 屬性值被復制 on.push inside loop

首先是簡單示例,然后是實際代碼示例:

   flattenedWorkouts.forEach((currAlias,index) =>{
       
        const obj ={}
        const newMemberAttributes = Object.assign(obj, { alias: currAlias });
        newMemberAttributes.alias.indexID= index
                     
            console.log("memberAttributes:", newMemberAttributes);
         
            output.push(newMemberAttributes.alias)
    
    })

不正確的 FlattenedWorkout 元素的片段......有 100 個所以不包括所有 + 我已經修剪了 object:

  Array [
      Object {
        "Round": "AMRAP 1",
        "indexID": 6,
   
      },
  Object {
        "Round": "AMRAP 1",
        "indexID": 6,
   
      },
  Object {
        "Round": "AMRAP 1",
        "indexID": 6,
   
      },

我希望看到的:

 Object {
        "Round": "AMRAP 1",
        "indexID": 6,
   
      },
  Object {
        "Round": "AMRAP 1",
        "indexID": 7,
   
      },
  Object {
        "Round": "AMRAP 1",
        "indexID": 8,
   
      },

實際問題。 下面是起始Object。

 var WorkoutDetail = [ //Dummy item to act as begin of carasoul { RoundID: 1, Round: 'AMRAP 1', NumberOfSets: 3, Activity: [{ key: '1', title: 'AMRAP 1', description: "Banded curtsy lunge to side leg raise", }, { key: '2', title: 'AMRAP 1', description: "Inchworm with push-up", }, { key: '3', title: 'AMRAP 1', description: "Static lunge with single arm press", } ] }, { RoundID: 2, Round: 'AMRAP 2', NumberOfSets: 2, Activity: [{ key: '4', title: 'AMRAP 2', description: "Side plank to leg extension", }, { key: '5', title: 'AMRAP 2', description: "Burpee to bench jump", }, { key: '6', title: 'AMRAP 2', description: "Banded heel tap jump squat", } ] }, { RoundID: 3, Round: 'AMRAP 3', NumberOfSets: 1, Activity: [{ key: '7', title: 'AMRAP 3', description: "Weighted pike plank", }, { key: '8', title: 'AMRAP 3', description: "Incline push up", }, { //Dummy item to make as caboose key: '9', title: 'AMRAP 3', description: "Weighted pike plank", }, //Dummy item to make as caboose in carasoul ] } ] // Next a Method I am using to loop over this object and * flatten * it out: var FlatWorkoutDetail = () => { var flattenedWorkouts = [] var iterationNumber = 0 //Each Round WorkoutDetail.forEach(x => { for (let i = 1; i <= x.NumberOfSets; i++) { for (let a = 0; a < x.Activity.length; a++) { var obj = x.Activity[a] obj.Round = x.Round obj.SetNumber = i flattenedWorkouts.push(obj) iterationNumber++; } } }) return flattenedWorkouts } // Simple forEach Solution: var FlatWorkoutDetailOutput = (val) => { val.forEach((obj, i) => obj.indexID = i); } // Execute the functions: const TestArray = FlatWorkoutDetail() const TestArray2 = FlatWorkoutDetailOutput(TestArray) console.log(TestArray);

最終 output 不正確。 6 是起始索引,14 重復兩次:

Array [
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Banded curtsy lunge to side leg raise",
    "image": null,
    "indexID": 6,
    "key": "1",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Test.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Inchworm with push-up",
    "image": null,
    "indexID": 7,
    "key": "2",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout3.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Static lunge with single arm press",
    "image": null,
    "indexID": 8,
    "key": "3",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Banded curtsy lunge to side leg raise",
    "image": null,
    "indexID": 6,
    "key": "1",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Test.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Inchworm with push-up",
    "image": null,
    "indexID": 7,
    "key": "2",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout3.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Static lunge with single arm press",
    "image": null,
    "indexID": 8,
    "key": "3",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Banded curtsy lunge to side leg raise",
    "image": null,
    "indexID": 6,
    "key": "1",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Test.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Inchworm with push-up",
    "image": null,
    "indexID": 7,
    "key": "2",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout3.mp4",
  },
  Object {
    "Round": "AMRAP 1",
    "SetNumber": 3,
    "description": "Static lunge with single arm press",
    "image": null,
    "indexID": 8,
    "key": "3",
    "time": " 45 Seconds",
    "title": "AMRAP 1",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 2",
    "SetNumber": 2,
    "description": "Side plank to leg extension",
    "image": null,
    "indexID": 12,
    "key": "4",
    "time": " 45 Seconds",
    "title": "AMRAP 2",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 2",
    "SetNumber": 2,
    "description": "Burpee to bench jump",
    "image": null,
    "indexID": 13,
    "key": "5",
    "time": " 45 Seconds",
    "title": "AMRAP 2",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 2",
    "SetNumber": 2,
    "description": "Banded heel tap jump squat",
    "image": null,
    "indexID": 14,
    "key": "6",
    "time": " 45 Seconds",
    "title": "AMRAP 2",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 2",
    "SetNumber": 2,
    "description": "Side plank to leg extension",
    "image": null,
    "indexID": 12,
    "key": "4",
    "time": " 45 Seconds",
    "title": "AMRAP 2",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 2",
    "SetNumber": 2,
    "description": "Burpee to bench jump",
    "image": null,
    "indexID": 13,
    "key": "5",
    "time": " 45 Seconds",
    "title": "AMRAP 2",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 2",
    "SetNumber": 2,
    "description": "Banded heel tap jump squat",
    "image": null,
    "indexID": 14,
    "key": "6",
    "time": " 45 Seconds",
    "title": "AMRAP 2",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 3",
    "SetNumber": 1,
    "description": "Weighted pike plank",
    "image": null,
    "indexID": 15,
    "key": "7",
    "time": " 45 Seconds",
    "title": "AMRAP 3",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 3",
    "SetNumber": 1,
    "description": "Incline push up",
    "image": null,
    "indexID": 16,
    "key": "8",
    "time": " 45 Seconds",
    "title": "AMRAP 3",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
  Object {
    "Round": "AMRAP 3",
    "SetNumber": 1,
    "description": "Weighted pike plank",
    "image": null,
    "indexID": 17,
    "key": "9",
    "time": " 45 Seconds",
    "title": "AMRAP 3",
    "video": "https://boolin-api2.herokuapp.com/fetchImage//Uploads/Game3899-Workout4.mp4",
  },
]

結果中的重復索引值無法由發布的代碼解釋。

在代碼中:

flattenedWorkouts.forEach((currAlias,index) =>{

flattenedWorkouts沒有示例,所以我將使用:

[{name: 'A'},{name: 'B'},{name: 'C'}];

然后是:

    const obj ={}
    const newMemberAttributes = Object.assign(obj, { alias: currAlias });

結果是objnewMemberAttributes引用了相同的 object。 它與以下內容相同:

let obj = {alias: currAlias};
let newMemberAttributes = obj;

Object.assign進行淺拷貝,因此:

newMemberAttributes.alias === currAlias

即傳遞給forEach的原始 object 被分配給newMemberAttributes.alias ,它的屬性和值不會被復制。 對原始 object 的任何更改都將反映在newMemberAttributes.alias中。

后來有:

        output.push({ ...obj, alias: currAlias })

output沒有在任何地方定義,所以我添加了let output = [] 由於obj引用了與 newMemberAttributes 相同的object ,因此使用哪一個並不重要。

obj的解構和與別名的合並意味着重復的屬性被覆蓋。 obj只有兩個屬性: aliasindexID ,所以它自己的alias屬性在與currAlias的合並中被覆蓋。 這幾乎沒有實際效果,因為無論如何這些值都是相同的(即它們都是對currAlias對象的引用)。

如果您要做的只是將indexID屬性添加到flattenedWorkouts中的對象,那么只需執行以下操作:

flattenedWorkouts.forEach((obj, i) => obj.indexID = i);

另一方面,如果您想先復制對象,則在添加indexID之前使用mapObject.assign復制它們:

let output = flattenedWorkouts.map((obj, i) => Object.assign({}, obj, {indexID: i}));

請注意, Object.assign執行的是淺拷貝,因此更深的對象是引用,而不是拷貝。

以下代碼可能會解決問題。 或不。

 let flattenedWorkouts = [{name: 'A'}, {name: 'B'}, {name: 'C'}]; let output = []; flattenedWorkouts.forEach((currAlias, index) => { let obj = {}; let newMemberAttributes = Object.assign(obj, {alias: currAlias}); console.log('obj === newMemberAttributes: ' + (obj === newMemberAttributes)); console.log('obj.alias === currAlias: ' + (obj.alias === currAlias)); newMemberAttributes.alias.indexID = index; console.log('iteration ' + index + ' memberAttributes\n', newMemberAttributes); output.push({...obj, alias: currAlias}); }) console.log('output ' + JSON.stringify(output));

如果意圖是跨屬性和值復制並添加indexID屬性,請考慮基於forEach的以下內容(但另請參閱下面的map示例):

 let arr = [{name: 'A'},{name: 'B'},{name: 'C'}]; let result = []; arr.forEach((obj, i) => { let newObj = Object.assign({},obj, {indexID: i} ); result.push(newObj); }); console.log(result); // Check that original array objects aren't changed console.log( 'Compare values:\n' + JSON.stringify(arr[0]) + '\n' + JSON.stringify(result[0]) ); // Check identity console.log('arr[0] === result[0]? ' + (arr[0] === result[0]));

使用map 的示例:

 let arr = [{name: 'A'},{name: 'B'},{name: 'C'}]; let output = arr.map((obj, i) => Object.assign({}, obj, {indexID: i})); console.log(output);

我不知道您的代碼中還發生了什么,但是您對初始的 object 進行了很多變異。 變異是萬惡之源,盡量避免它,就像 COVID 一樣。

這樣做,它應該可以解決您的索引問題。

var FlatWorkoutDetailOutput = (val) =>{
                              // shallow copy of the object, it only works cause the object is flat
  return val.map((obj, i) => ({...obj, indexID: i}));

}

現在TestArray將具有與以前相同的錯誤,但TestArray2將具有正確的indexID

根據經驗,每次您希望 object 看起來與原來不同時,請在原來的基礎上創建一個新的 object。 如果您有一個對象數組,請使用map並返回一個新數組,其中包含基於原始對象的新對象。

所以在你以前的代碼中而不是這樣做

var obj = x.Activity[a]
obj.Round =  x.Round
obj.SetNumber = i
flattenedWorkouts.push(obj)
iterationNumber ++;

做這個

var originalObj = x.Activity[a]
var newObj = { ...originalObj } // this is a shallow copy, if you want to copy deep nested objects look up some library
newObj.SetNumber = i
flattenedWorkouts.push(newObj)
iterationNumber ++;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM