Типичным объявлением переменной является
extern int x;
. Поскольку это только объявление, требуется одно определение. Соответствующим определением будет:
int x;
Например, следующее генерирует ошибку:
extern int x;
int main()
{
x = 0;
}
//int x; // uncomment this line for successful definition
Аналогичные замечания относятся к функциям. Объявление функции без ее определения приводит к ошибке:
void foo(); // declaration only
int main()
{
foo();
}
//void foo() {} //uncomment this line for successful definition
Будьте осторожны, чтобы выполняемая вами функция точно соответствовала той, которую вы объявили. Например, у вас могут быть несогласованные cv-квалификаторы:
void foo(int& x);
int main()
{
int x;
foo(x);
}
void foo(const int& x) {} //different function, doesn't provide a definition
//for void foo(int& x)
Другие примеры несоответствий включают
Сообщение об ошибке из компилятора часто дает вам полное объявление переменной или функции, которая была объявлена, но не определена. Сравните его с определением, которое вы указали. Убедитесь, что каждая деталь соответствует.
Метод array.slice может извлечь срез из начала, середины или конца массива для любых целей, которые вам нужны, без изменения исходного массива.
var i,j,temparray,chunk = 10;
for (i=0,j=array.length; i<j; i+=chunk) {
temparray = array.slice(i,i+chunk);
// do whatever
}
Я создал следующий JSFiddle , чтобы продемонстрировать мой подход к вашему вопросу.
(function() {
// Sample arrays
var //elements = ["0", "1", "2", "3", "4", "5", "6", "7"],
elements = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43"];
var splitElements = [],
delimiter = 10; // Change this value as needed
// parameters: array, number of elements to split the array by
if(elements.length > delimiter){
splitElements = splitArray(elements, delimiter);
}
else {
// No need to do anything if the array's length is less than the delimiter
splitElements = elements;
}
//Displaying result in console
for(element in splitElements){
if(splitElements.hasOwnProperty(element)){
console.log(element + " | " + splitElements[element]);
}
}
})();
function splitArray(elements, delimiter) {
var elements_length = elements.length;
if (elements_length > delimiter) {
var myArrays = [], // parent array, used to store each sub array
first = 0, // used to capture the first element in each sub array
index = 0; // used to set the index of each sub array
for (var i = 0; i < elements_length; ++i) {
if (i % delimiter === 0) {
// Capture the first element of each sub array from the original array, when i is a modulus factor of the delimiter.
first = i;
} else if (delimiter - (i % delimiter) === 1) {
// Build each sub array, from the original array, sliced every time the i one minus the modulus factor of the delimiter.
index = (i + 1) / delimiter - 1;
myArrays[index] = elements.slice(first, i + 1);
}
else if(i + 1 === elements_length){
// Build the last sub array which contain delimiter number or less elements
myArrays[index + 1] = elements.slice(first, i + 1);
}
}
// Returned is an array of arrays
return myArrays;
}
}
Прежде всего , У меня есть два примера: массив с менее чем восемью элементами, другой с массивом с более чем восемью элементами (комментарий, который вы не хотите использовать).
Затем я проверяю размер массив, простой, но необходимый, чтобы избежать дополнительных вычислений. Отсюда, если массив соответствует критериям (размер массива> delimiter
), мы переходим к функции splitArray
.
Функция splitArray
принимает разделитель (это означает 8, так как это то, что вы хотите разделить), и сам массив. Поскольку мы многократно используем длину массива, я кэширую его в переменной, а также first
и last
.
first
представляет позицию первого элемента в массив. Этот массив представляет собой массив из 8 элементов. Поэтому для определения первого элемента мы используем оператор модуля .
myArrays
- это массив массивов. В нем мы будем хранить в каждом индексе любой подвальный массив размером 8 или ниже. Это ключевая стратегия в приведенном ниже алгоритме.
index
представляет индекс для переменной myArrays
. Каждый раз, когда необходимо сохранить вспомогательный массив из 8 элементов или меньше, его необходимо сохранить в соответствующем индексе. Итак, если у нас есть 27 элементов, это означает 4 массива. Первый, второй и третий массивы будут содержать по 8 элементов. У последнего будет только 3 элемента. Таким образом, index
будет равен 0, 1, 2 и 3.
Сложная часть просто вычисляет математику и оптимизирует ее как можно лучше. Например, else if (delimiter - (i % delimiter) === 1)
это найти последний элемент, который должен идти в массиве, когда массив будет заполнен (пример: содержать 10 элементов).
Этот код работает для каждого отдельного сценария, вы можете даже измените значение delimiter
в соответствии с размером любого размера, который вы хотите получить. Довольно сладкое право: -)
Есть вопросы? Не стесняйтесь спрашивать в комментариях ниже.
Вот версия ES6, использующая reduce
perChunk = 2 // items per chunk
inputArray = ['a','b','c','d','e']
inputArray.reduce((resultArray, item, index) => {
const chunkIndex = Math.floor(index/perChunk)
if(!resultArray[chunkIndex]) {
resultArray[chunkIndex] = [] // start a new chunk
}
resultArray[chunkIndex].push(item)
return resultArray
}, [])
// result: [['a','b'], ['c','d'], ['e']]
. И вы готовы цеплять дальнейшие преобразования карты / уменьшения. Ваш входной массив остается неповрежденным
Если вы предпочитаете более короткую, но менее читаемую версию, вы можете посыпать некоторые concat
в микс для того же конечного результата:
inputArray.reduce((all,one,i) => {
const ch = Math.floor(i/perChunk);
all[ch] = [].concat((all[ch]||[]),one);
return all
}, [])
Я предпочел бы использовать метод splice :
var chunks = function(array, size) {
var results = [];
while (array.length) {
results.push(array.splice(0, size));
}
return results;
};
in coffeescript:
b = (a.splice(0, len) while a.length)
demo
a = [1, 2, 3, 4, 5, 6, 7]
b = (a.splice(0, 2) while a.length)
[ [ 1, 2 ],
[ 3, 4 ],
[ 5, 6 ],
[ 7 ] ]
Я тестировал разные ответы на jsperf.com. Результат доступен там: http://jsperf.com/chunk-mtds
И самым быстрым функционалом (и который работает из IE8) является этот:
function chunk(arr, chunkSize) {
var R = [];
for (var i=0,len=arr.length; i<len; i+=chunkSize)
R.push(arr.slice(i,i+chunkSize));
return R;
}
Я просто написал это с помощью функции groupBy.
// utils
const group = (source) => ({
by: (grouping) => {
const groups = source.reduce((accumulator, item) => {
const name = JSON.stringify(grouping(item));
accumulator[name] = accumulator[name] || [];
accumulator[name].push(item);
return accumulator;
}, {});
return Object.keys(groups).map(key => groups[key]);
}
});
const chunk = (source, size) => group(source.map((item, index) => ({ item, index })))
.by(x => Math.floor(x.index / size))
.map(x => x.map(v => v.item));
// 103 items
const arr = [6,2,6,6,0,7,4,9,3,1,9,6,1,2,7,8,3,3,4,6,8,7,6,9,3,6,3,5,0,9,3,7,0,4,1,9,7,5,7,4,3,4,8,9,0,5,1,0,0,8,0,5,8,3,2,5,6,9,0,0,1,5,1,7,0,6,1,6,8,4,9,8,9,1,6,5,4,9,1,6,6,1,8,3,5,5,7,0,8,3,1,7,1,1,7,6,4,9,7,0,5,1,0];
const chunks = chunk(arr, 10);
console.log(JSON.stringify(chunks));
Изменено из ответа dbaseman: https://stackoverflow.com/a/10456344/711085
Object.defineProperty(Array.prototype, 'chunk_inefficient', {
value: function(chunkSize) {
var array=this;
return [].concat.apply([],
array.map(function(elem,i) {
return i%chunkSize ? [] : [array.slice(i,i+chunkSize)];
})
);
}
});
Демонстрация:
> [1,2,3,4,5,6,7].chunk_inefficient(3)
[[1,2,3],[4,5,6],[7]]
< hr> второстепенное дополнение :
Следует отметить, что вышеизложенное - это не очень элегантное (на мой взгляд) обходное решение для использования Array.map
. В основном это означает, что ~ является конкатенацией:
[[1,2,3]]~[]~[]~[] ~ [[4,5,6]]~[]~[]~[] ~ [[7]]
Он имеет такое же асимптотическое время работы, как и метод ниже, но, возможно, худший постоянный фактор из-за создания пустых списков. Можно было бы переписать это следующим образом (в основном так же, как метод Блаземонгера, поэтому я не изначально представил этот ответ):
Более эффективный метод:
Object.defineProperty(Array.prototype, 'chunk', {
value: function(chunkSize) {
var R = [];
for (var i=0; i<this.length; i+=chunkSize)
R.push(this.slice(i,i+chunkSize));
return R;
}
});
// refresh page if experimenting and you already defined Array.prototype.chunk
Мой предпочтительный способ в настоящее время является приведенным выше или одним из следующих:
Array.range = function(n) {
// Array.range(5) --> [0,1,2,3,4]
return Array.apply(null,Array(n)).map((x,i) => i)
};
Object.defineProperty(Array.prototype, 'chunk', {
value: function(n) {
// ACTUAL CODE FOR CHUNKING ARRAY:
return Array.range(Math.ceil(this.length/n)).map((x,i) => this.slice(i*n,i*n+n));
}
});
Демонстрация:
> JSON.stringify( Array.range(10).chunk(3) );
[[1,2,3],[4,5,6],[7,8,9],[10]]
Или, если вы не хотите использовать функцию Array.range, это на самом деле просто однострочный (исключая пух):
var ceil = Math.ceil;
Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
return Array(ceil(this.length/n)).fill().map((_,i) => this.slice(i*n,i*n+n));
}});
или
Object.defineProperty(Array.prototype, 'chunk', {value: function(n) {
return Array.from(Array(ceil(this.length/n)), (_,i)=>this.slice(i*n,i*n+n));
}});
Это простое решение, использующее решение @Blazemonger
function array_chunk(arr, size){
// initialize vars
var i,
j = arr.length,
tempArray = [];
// loop through and jump based on size
for (i=0; i<j; i+=size) {
// slice chunk of arr and push to tempArray
tempArray.push(arr.slice(i,i+size));
}
// return temp array (chunck)
return tempArray
}
. Это привело к тому, что у меня получился поток, надеюсь, что это поможет кому-то другому. :)
EDIT: @ mblase75 добавил более сжатый код к более раннему ответу, пока я писал, поэтому я рекомендую пойти с его решением.
Вы могли бы использовать такой код:
var longArray = ["Element 1","Element 2","Element 3", /*...*/];
var smallerArrays = []; // will contain the sub-arrays of 10 elements each
var arraySize = 10;
for (var i=0;i<Math.ceil(longArray.length/arraySize);i++) {
smallerArrays.push(longArray.slice(i*arraySize,i*arraySize+arraySize));
}
Измените значение arraySize
, чтобы изменить максимальную длину меньших массивов.
Однострочный подход ES6, основанный на методах Array.prototype
reduce
и push
:
const doChunk = (list, size) => list.reduce((r, v) =>
(!r.length || r[r.length - 1].length === size ?
r.push([v]) : r[r.length - 1].push(v)) && r
, []);
console.log(doChunk([0,1,2,3,4,5,6,7,8,9,10,11,12], 5));
// [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9], [10, 11, 12]]
Старайтесь избегать обмана с родными прототипами, в том числе Array.prototype, если вы не знаете, кто будет потреблять ваш код (третьи стороны, коллеги, себя в более позднюю дату и т. д.).
Есть способы безопасно расширять прототипы (но не во всех браузерах), и есть способы безопасного использования объектов, созданных из расширенных прототипов, но лучшим правилом является следовать принципу наименьшего сюрприза и вообще избегайте этих практик.
Если у вас есть время, просмотрите доклад Андрея Дюпона в 2011 году, «Все разрешено: расширение встроенных модулей» , для хорошей дискуссии по этому вопросу ,
Но вернемся к вопросу, в то время как вышеприведенные решения будут работать, они слишком сложны и требуют ненужных вычислительных издержек. Вот мое решение:
function chunk (arr, len) {
var chunks = [],
i = 0,
n = arr.length;
while (i < n) {
chunks.push(arr.slice(i, i += len));
}
return chunks;
}
// Optionally, you can do the following to avoid cluttering the global namespace:
Array.chunk = chunk;
В настоящее время вы можете использовать функцию блока lodash для разбиения массива на меньшие массивы https://lodash.com/docs#chunk Не нужно больше болтаться с петлями!
Если вы используете версию EcmaScript> = 5.1, вы можете реализовать функциональную версию chunk()
, используя array.reduce () , которая имеет сложность O (N):
function chunk(chunkSize, array) {
return array.reduce(function(previous, current) {
var chunk;
if (previous.length === 0 ||
previous[previous.length -1].length === chunkSize) {
chunk = []; // 1
previous.push(chunk); // 2
}
else {
chunk = previous[previous.length -1]; // 3
}
chunk.push(current); // 4
return previous; // 5
}, []); // 6
}
console.log(chunk(2, ['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b' ], [ 'c', 'd' ], [ 'e' ] ]
Объяснение каждого // nbr
выше:
chunkSize
items Каррирование на основе chunkSize
:
var chunk3 = function(array) {
return chunk(3, array);
};
console.log(chunk3(['a', 'b', 'c', 'd', 'e']));
// prints [ [ 'a', 'b', 'c' ], [ 'd', 'e' ] ]
Вы можете добавить функцию chunk()
к глобальному объекту Array
:
Object.defineProperty(Array.prototype, 'chunk', {
value: function(chunkSize) {
return this.reduce(function(previous, current) {
var chunk;
if (previous.length === 0 ||
previous[previous.length -1].length === chunkSize) {
chunk = [];
previous.push(chunk);
}
else {
chunk = previous[previous.length -1];
}
chunk.push(current);
return previous;
}, []);
}
});
console.log(['a', 'b', 'c', 'd', 'e'].chunk(4));
// prints [ [ 'a', 'b', 'c' 'd' ], [ 'e' ] ]
results = []
chunk_size = 10
while(array.length > 0){
results.push(array.splice(0, chunk_size))
}
Здесь аккуратный & amp; оптимизированная реализация функции chunk()
. Предполагая размер блока по умолчанию 10
.
var chunk = function(list, chunkSize) {
if (!list.length) {
return [];
}
if (typeof chunkSize === undefined) {
chunkSize = 10;
}
var i, j, t, chunks = [];
for (i = 0, j = list.length; i < j; i += chunkSize) {
t = list.slice(i, i + chunkSize);
chunks.push(t);
}
return chunks;
};
//calling function
var list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var chunks = chunk(list);
Это наиболее эффективное и прямолинейное решение, о котором я мог подумать:
function chunk(array, chunkSize) {
let chunkCount = Math.ceil(array.length / chunkSize);
let chunks = new Array(chunkCount);
for(let i = 0, j = 0, k = chunkSize; i < chunkCount; ++i) {
chunks[i] = array.slice(j, k);
j = k;
k += chunkSize;
}
return chunks;
}
Я немного изменил BlazeMonger для использования для объекта jQuery ..
var $list = $('li'),
$listRows = [];
for (var i = 0, len = $list.length, chunk = 4, n = 0; i < len; i += chunk, n++) {
$listRows[n] = $list.slice(i, i + chunk);
}
# in coffeescript
# assume "ar" is the original array
# newAr is the new array of arrays
newAr = []
chunk = 10
for i in [0... ar.length] by chunk
newAr.push ar[i... i+chunk]
# or, print out the elements one line per chunk
for i in [0... ar.length] by chunk
console.log ar[i... i+chunk].join ' '
Вот мой подход с использованием понимания списка Coffeescript. Огромная статья, в которой подробно описываются соображения в Coffeescript, может быть найдена здесь .
chunk: (arr, size) ->
chunks = (arr.slice(index, index+size) for item, index in arr by size)
return chunks
И это будет моим вкладом в эту тему. Я думаю, что .reduce()
- лучший способ.
var segment = (arr, n) => arr.reduce((r,e,i) => i%n ? (r[r.length-1].push(e), r)
: (r.push([e]), r), []),
arr = Array.from({length: 31}).map((_,i) => i+1);
res = segment(arr,7);
console.log(JSON.stringify(res));
Но вышеприведенная реализация не очень эффективна, поскольку .reduce()
проходит через все arr
. Более эффективный подход (очень близкий к самому быстрому императивному решению) будет, итерации по уменьшенному (чтобы быть разбитым) массивом, поскольку мы можем заранее вычислить его размер на Math.ceil(arr/n);
. Когда у нас есть пустой массив результатов, подобный Array(Math.ceil(arr.length/n)).fill();
, остальное состоит в отображении в него ломтиков массива arr
.
function chunk(arr,n){
var r = Array(Math.ceil(arr.length/n)).fill();
return r.map((e,i) => arr.slice(i*n, i*n+n));
}
arr = Array.from({length: 31}).map((_,i) => i+1);
res = chunk(arr,7);
console.log(JSON.stringify(res));
Старый вопрос: Новый ответ! Я на самом деле работал с ответом на этот вопрос, и у меня улучшился друг! Итак, вот оно:
Array.prototype.chunk = function ( n ) {
if ( !this.length ) {
return [];
}
return [ this.slice( 0, n ) ].concat( this.slice(n).chunk(n) );
};
[1,2,3,4,5,6,7,8,9,0].chunk(3);
> [[1,2,3],[4,5,6],[7,8,9],[0]]
function* chunkArray(array,size=1){
var clone = array.slice(0);
while (clone.length>0)
yield clone.splice(0,size);
};
var a = new Array(100).fill().map((x,index)=>index);
for(const c of chunkArray(a,10))
console.log(c);
Однострочный в ECMA 6
const [list,chuckSize] = [[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15], 6]
new Array(Math.ceil(list.length / chuckSize)).fill().map(_ => list.splice(0,chuckSize))
Было много ответов, но это то, что я использую:
const chunk = (arr, size) =>
arr
.reduce((acc, _, i) =>
(i % size)
? acc
: [...acc, arr.slice(i, i + size)]
, [])
// USAGE
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
chunk(numbers, 3)
// [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Сначала проверьте остаток при делении индекса на размер блока.
Если есть остальная часть затем просто возвращает массив накопителей.
Если нет остатка, тогда индекс делится на размер куска, поэтому возьмите срез из исходного массива (начиная с текущего индекса) и добавьте его в массив аккумуляторов.
Итак, возвращаемый массив накопителей для каждой итерации сокращения выглядит примерно так:
// 0: [[1, 2, 3, 4]]
// 1: [[1, 2, 3, 4]]
// 2: [[1, 2, 3, 4]]
// 3: [[1, 2, 3, 4]]
// 4: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 5: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 6: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 7: [[1, 2, 3, 4], [5, 6, 7, 8]]
// 8: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
// 9: [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
Вот не мутирующее решение, использующее только рекурсию и срез ().
const splitToChunks = (arr, chunkSize, acc = []) => (
arr.length > chunkSize ?
splitToChunks(
arr.slice(chunkSize),
chunkSize,
[...acc, arr.slice(0, chunkSize)]
) :
[...acc, arr]
);
Тогда просто используйте его, как splitToChunks([1, 2, 3, 4, 5], 3)
, чтобы получить [[1, 2, 3], [4, 5]]
.
Здесь это скрипка для вас: https://jsfiddle.net/6wtrbx6k/2/
Вот решение, использующее ImmutableJS, где items
- это неизменяемый список, а size
- необходимый размер группировки.
const partition = ((items, size) => {
return items.groupBy((items, i) => Math.floor(i/size))
})
Я стремился к созданию простого не мутирующего решения в чистом ES6. Особенности javascript заставляют заполнить пустой массив перед отображением: - (
function chunk(a, l) {
return new Array(Math.ceil(a.length / l)).fill(0)
.map((_, n) => a.slice(n*l, n*l + l));
}
Эта версия с рекурсией кажется более простой и более убедительной:
function chunk(a, l) {
if (a.length == 0) return [];
else return [a.slice(0, l)].concat(chunk(a.slice(l), l));
}
Смешно слабый массив функции ES6 создают хорошие головоломки: -)
Хорошо, давайте начнем с довольно жесткого:
function chunk(arr, n) {
return arr.slice(0,(arr.length+n-1)/n|0).
map(function(c,i) { return arr.slice(n*i,n*i+n); });
}
Который используется следующим образом:
chunk([1,2,3,4,5,6,7], 2);
Тогда у нас есть эта плотная редукционная функция:
function chunker(p, c, i) {
(p[i/this|0] = p[i/this|0] || []).push(c);
return p;
}
Используется следующим образом:
[1,2,3,4,5,6,7].reduce(chunker.bind(3),[]);
Так как котенок умирает, когда мы привязываем this
к числу, мы можем сделать ручное currying следующим образом:
// Fluent alternative API without prototype hacks.
function chunker(n) {
return function(p, c, i) {
(p[i/n|0] = p[i/n|0] || []).push(c);
return p;
};
}
Используется следующим образом:
[1,2,3,4,5,6,7].reduce(chunker(3),[]);
Затем все еще довольно тугая функция, которая делает все это за один раз:
function chunk(arr, n) {
return arr.reduce(function(p, cur, i) {
(p[i/n|0] = p[i/n|0] || []).push(cur);
return p;
},[]);
}
chunk([1,2,3,4,5,6,7], 3);
Создал пакет npm для этого https://www.npmjs.com/package/array.chunk
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, size + i));
}
return result;