alltones
数组包含音乐音阶中的所有可能音符。
var alltones = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" ];
我想获取用户输入的音调,然后构造一个包含数组元素的列表。
假设我从alltones[5]
或"F"
开始,并希望从该点获取数组的每个第二个元素并将其放入我的列表中,直到我回到"F"
。该数组更像是一个圆而不是直列表。一旦循环到达最后一个元素,我就不太确定数组是如何运作的。
我是否可以根据用户输入生成新数组来解决问题。或者有没有一种方法可以让JavaScript知道在数组到达末尾时循环回到数组的开头,这样它就像将数组视为一个圆圈一样?
一个例子:
用户输入= F
我正在寻找的输出是从F计算(每两个项目),直到我们回到数组到F
所以期望的输出将是=> F G A B C#D#
答案 0 :(得分:2)
没有existing Array method可以执行您想要的操作,但可以使用Array.prototype.slice
和Array.prototype.concat
轻松定义一个:
// move i elements from the start of the array to the end of the array
Array.prototype.lcycle = function(i) {
var xs = this.slice(0,i);
var ys = this.slice(i);
return ys.concat(xs)
};
// move i elements from the end of the array to the start of the array
Array.prototype.rcycle = function(i) {
var xs = this.slice(0,-i);
var ys = this.slice(-i);
return ys.concat(xs);
};
然后您可以使用lcycle
和rcycle
作为常规数组方法:
>>> alltones.lcycle(3)
[ "D#" , "E" , "F" , "F#" , "G" , "G#" , "A" , "A#" , "B" , "C" , "C#" , "D" ]
>>> alltones.rcycle(4)
[ "G#" , "A" , "A#" , "B" , "C" , "C#" , "D" , "D#" , "E" , "F" , "F#" , "G" ]
请注意,这两个方法都返回一个新数组。如果您想改变原始数组,可以使用Array.prototype.splice
定义类似的方法。
// move i elements from the start of the array to the end of the array, mutating the original array
Array.prototype.lcycle_m = function(i) {
var args = this.splice(0,i);
args.unshift(0);
args.unshift(this.length);
this.splice.apply(this, args);
};
// move i elements from the end of the array to the start of the array, mutating the original array
Array.prototype.rcycle_m = function(i) {
var args = this.splice(-i);
args.unshift(0);
args.unshift(0);
this.splice.apply(this, args);
};
同样,您可以使用lcycle_m
和rcycle_m
作为常规数组方法:
>>> alltones.lcycle_m(3)
>>> alltones
[ "D#" , "E" , "F" , "F#" , "G" , "G#" , "A" , "A#" , "B" , "C" , "C#" , "D" ]
>>> alltones.rcycle_m(3)
>>> alltones
[ "C" , "C#" , "D" , "D#" , "E" , "F" , "F#" , "G" , "G#" , "A" , "A#" , "B" ]
答案 1 :(得分:1)
你可以在两个循环中完成,因为JS没有内置的支持圈。
for (var i = users_input; i < alltones.length; i += 1) {
... use alltones[i] for calc
}
for (var i = 0; i < users_input; i += 1) {
... use alltones[i] for calc
}
或那条线上的东西。 实际上不需要创建新阵列。
答案 2 :(得分:1)
这个怎么样:
function getNotes(index) {
var list = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" ];
return list.splice(index).concat(list).filter(function(note, i) {
return i % 2 == 0;
});
}
getNotes(3); // ["D#", "F", "G", "A", "B", "C#"]
这样做首先重新组织数组,以便将所选索引转移到开头,并将之前的所有内容移动到结尾,然后过滤掉所有其他注释。如果您希望getNotes
函数使用字符串,则可以使用indexOf
方法。 indexOf
和filter
(上面使用过的)是ECMAScript 5的一部分,因此您可能需要根据您计划支持的浏览器进行填充。
答案 3 :(得分:1)
这是在数组到达结尾时循环回到数组开头的方法:
arr[index%arr.length]
,如果index
&gt; arr.length
,它将“循环”到开头。
这种技术很有效,适用于几乎所有语言。
var alltones = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" ];
function generateMusic(startIndex) {
var i = 0, music = [],
tonesCount = alltones.length
do {
music.push(alltones[(startIndex+i)%tonesCount]);
} while ((i+=2) < tonesCount);
return music;
}
结果:
console.log(generateMusic(3)); //["D#", "F", "G", "A", "B", "C#"]
console.log(generateMusic(5)); //["F", "G", "A", "B", "C#", "D#"]
答案 4 :(得分:0)
在两个循环中执行一个数组成员从初始点开始,另一个从头开始是更好的方法;这里的关键是从头开始,取决于我们在数组末尾的位置。
你可以创建像
这样的通用函数 var alltones = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" ];
function build_tones(arr, start, jump_by){
var new_list = [];
//finish first iteration and get the last index so that we can offset accordingly from the beginning
var get_last = (function(){
var last;
for(i = start; i <= arr.length; i+=jump_by){
new_list.push(arr[i]);
last = i;
}
return last;
})();
//do the second iteration by picking up from the index left and continue from first
for(i = 0 + arr.length%get_last; i < start; i+=jump_by){
new_list.push(arr[i]);
}
return new_list;
}
var result = build_tones(alltones, 5, 2);
console.log(result);