如何在不使用“i-1”、“i-2”等的情况下动态引用数组中的前一项?

function play_music(song) {
  let played_notes = [];
  let secs = [];
  let position = [];
  let secs_to_wait = 0;
  let time_elapsed = 0;

  console.log("Song started.")

  for (let key in song) {
    played_notes.push(song[key].note);
    secs.push(song[key].lasts);
    position.push(song[key].starts_at);
  }

  for (let i in position) {
    if (position[i] > position[i - 1]) {
      secs_to_wait = position[i] - secs_to_wait;
      console.log("Wait " + secs_to_wait + " second(s).");
      console.log("Play " + played_notes[i]);
    } else {
      console.log("Play " + played_notes[i]);
    }

    if (position[i] == position[i - 1] && secs[i] == secs[i - 1] || position[i] + secs[i] == secs[i - 1]) {
      //do nothing.
    } else {
      time_elapsed += secs[i];
    }

    if ((secs[i] + position[i]) < time_elapsed || secs[i] < time_elapsed) {
      console.log(played_notes[i] + " released.")
    }
  }
  return "Song ends.";
}

let my_song = [{
    note: 'C',starts_at: 0,lasts: 4
  },{
    note: 'E',{
    note: 'G',starts_at: 2,lasts: 2
  },{
    note: 'G#',starts_at: 3,{
    note: 'Eb',lasts: 2
  }
];

console.log(play_music(my_song))

在这个程序中,我应该创建一个函数,该函数从一系列对象中按时间顺序返回音符的控制台消息,它们何时开始,在它们之间等待多长时间,以及何时释放这些音符。我在每个对象中有三个元素:音符名称、以秒为单位的起始位置以及持续时间(也以秒为单位)。

当我按索引遍历每个元素时,我的代码可以工作 90%,但是当我在控制台上返回“释放”消息时,我无法引用我所在索引之前的音符。而且如果我只输入以下内容,它将仅适用于元素的当前顺序,无论顺序如何,它都不会动态工作:

  if ((secs[i] + position[i]) < time_elapsed || secs[i] < time_elapsed){
     console.log((played_notes[i] + played_notes[i-1] + played_notes[i-2]) + " released.")
  }

现在,如果您运行之前显示的整个代码,只会释放“G”,不会释放“C”和“E”。后来,“G#”和“Eb”不会同时发布,而是“G#”播放并发布,然后“Eb”播放并发布。

更不用说我没有得到“等待 x 秒”。播放“G#”和“Eb”之前的消息。

所以有些东西不起作用,我希望最后得到的控制台输出是这样的:

Song started.
Play C
Play E
Wait 2 second(s).
Play G
Wait 1 second(s).
Play G#   
Play Eb
C released.
E released.
G released.
Wait 1 second(s).
G# released.
Eb released.
Song ends.

注意:我是初学者,对于这项任务,我不允许使用比 for 循环、while 循环、if 语句、数组和对象内置函数更高级的任何东西。所以 foreach 或其他任何东西都不会削减它。在这个意义上,请尽量保持简单,它可能需要更长的答案。

hygzp 回答:如何在不使用“i-1”、“i-2”等的情况下动态引用数组中的前一项?

首先对数组进行排序,使它们按位置顺序排列。那么上一个音符将始终是具有上一个索引的那个。

function play_music(song) {
  let played_notes = [];
  let secs = [];
  let position = [];
  let secs_to_wait = 0;
  let time_elapsed = 0;

  console.log("Song started.")

  // Sort song in order of start. Notes that start at the same time are in order of duration
  song.sort((a,b) => a.starts_at - b.starts_at || a.lasts - b.lasts);

  for (let key in song) {
    played_notes.push(song[key].note);
    secs.push(song[key].lasts);
    position.push(song[key].starts_at);
  }

  for (let i in position) {
    if (position[i] > position[i - 1]) {
      secs_to_wait = position[i] - secs_to_wait;
      console.log("Wait " + secs_to_wait + " second(s).");
      console.log("Play " + played_notes[i]);
    } else {
      console.log("Play " + played_notes[i]);
    }

    if (position[i] == position[i - 1] && secs[i] == secs[i - 1] || position[i] + secs[i] == secs[i - 1]) {
      //do nothing.
    } else {
      time_elapsed += secs[i];
    }

    if ((secs[i] + position[i]) < time_elapsed || secs[i] < time_elapsed) {
      console.log(played_notes[i] + " released.")
    }
  }
  return "Song ends.";
}

let my_song = [{
    note: 'C',starts_at: 0,lasts: 4
  },{
    note: 'E',{
    note: 'G',starts_at: 2,lasts: 2
  },{
    note: 'G#',starts_at: 3,{
    note: 'Eb',lasts: 2
  }
];

console.log(play_music(my_song))

,

@Barmar 是正确的,需要排序以保持 starts_at 的顺序,否则如果传入的歌曲带有错误设置的音符,则等待将不起作用。这个答案应该与预期的输出完全匹配,而无需使用 i-1 i-2 等。有趣的练习,谢谢。

function play_music(song) { 
    let elapsedInSeconds = -1; //song running time -1 song havent started yet
    let waitTimeInSeconds = 0; //wait time
    let songLengthInSeconds = -1; //total song length
    let noteToPlayIndex = 0; //note index to play in song

    song.sort((a,b) => {
        //the song total length will be the last note starts and how long it lasts
        const aNoteLengthInSeconds = a.starts_at + a.lasts;
        const bNoteLengthInSeconds = b.starts_at + b.lasts;
        //inject this here so we dont have to waste another loop
        songLengthInSeconds = Math.max(songLengthInSeconds,aNoteLengthInSeconds,bNoteLengthInSeconds);
        //we make sure the last note with longest duration be at the bottom of list
        return a.starts_at - b.starts_at || aNoteLengthInSeconds - bNoteLengthInSeconds; //a.lasts - b.lasts would work too
    });

    console.log('Song started.');
    //play until the end of the song
    while(elapsedInSeconds < songLengthInSeconds) {
        elapsedInSeconds++;
        //when we wait,a second went by so subtract and prevent going below 0
        waitTimeInSeconds = Math.max(0,--waitTimeInSeconds);
        //keep track if this is a waiting tick,we would need to track which keys needed to be released
        let isWaitingTick = waitTimeInSeconds > 0;
        for (let i=0; i < song.length; i++) {
            //if its waiting tick,we don't need to loop through the keys we haven't played
            if (isWaitingTick && i >= noteToPlayIndex) {
                break;
            }
            
            //keep track of the time that we need to release the keys
            const keyReleasedAt = song[i].starts_at + song[i].lasts;

            //doesnt matter if we are in waiting tick or not,if its ready to be release,then release it
            if (keyReleasedAt == elapsedInSeconds) { 
                console.log(song[i].note + " released.");
            }else if (!isWaitingTick) { 
                //play the key if its exact second to play
                if (song[i].starts_at == elapsedInSeconds) {
                    console.log("Play " + song[i].note,song[i].lasts);
                    noteToPlayIndex++;
                //other wise if it needs wait some time,we set our wait timer    
                } else if (song[i].starts_at > elapsedInSeconds) {
                    waitTimeInSeconds = song[i].starts_at - elapsedInSeconds;
                    console.log("Wait " + waitTimeInSeconds + " second(s).");
                    //break so it doesnt look at other notes; other keys would be >= of this note starts_at because of sort
                    break; 
                    
                //if we played all the keys then we should see if we need to wait any time for it to be released
                }  else if ( noteToPlayIndex >= song.length && keyReleasedAt > elapsedInSeconds) {
                    //wait time should be the diff between the second of the song it supposed to be released and current elapse time 
                    waitTimeInSeconds = keyReleasedAt - elapsedInSeconds;
                    console.log("Wait " + waitTimeInSeconds + " second(s).");
                    break;
                }
            }
        }
    }
    return "Song ends.";
}

let my_song = [
    {
        note: 'C',lasts: 4
    },{
        note: 'E',{
        note: 'G',lasts: 2
    },{
        note: 'G#',{
        note: 'Eb',];

console.log(play_music(my_song));

本文链接:https://www.f2er.com/417.html

大家都在问