运行 Google 个工作表的最大 ArrayFormula
Running Max ArrayFormula for Google Sheets
我有一个手动输入的号码列表
1
100
100
10
1
1000
10
1000
1
1000
100
10
我想得到 运行 max - 初始数字数组的每个子数组的最大值。我所说的子数组是指从 [A1]
到 [A2]
、从 [A1]
到 [A3]
、从 [A1]
到 [A4]
等的数字。
结果如下:
1
100
100
100
100
1000
1000
1000
1000
1000
1000
1000
可以将更多条目添加到初始号码列表中。
赏金
100 点赏金给了 。
这是 100500 行的速度测试:
自定义公式示例:
=INDEX(IF(A3:A="","",
runningTotal(A3:A,4)))
代码:
/**
* Get running total for the array of numbers
* by makhrov.max@gmail.com
*
* @param {array} numbers The array of numbers
* @param {number} total_types (1-dafault) sum, (2) avg, (3) min, (4) max, (5) count;
* 1-d array or number
* @param {number} limit number of last values to count next time.
* Set to 0 (defualt) to take all values
* @param {array} keys (optional) array of keys. Function will group result by keys
* @return The hex-code of cell background & font color
* @customfunction
*/
function runningTotal(numbers, total_types, limit, keys) {
// possible types to return
var oTypes = {
'1': 'sum',
'2': 'avg',
'3': 'min',
'4': 'max',
'5': 'count'
}
// checks and defaults
var errPre = ' ';
if( typeof numbers != "object" ) {
numbers = [ [numbers] ];
}
total_types = total_types || [1];
if( typeof total_types != "object" ) {
total_types = [ total_types ];
}
if( keys && typeof keys != "object" ) {
keys = [ [keys] ];
}
if (keys) {
if (numbers.length !== keys.length) {
throw errPre + 'Numbers(' +
numbers.length +
') and keys(' +
keys.length +
') are of different length'; }
}
// assign types
var types = [], type, k;
for (var i = 0; i < total_types.length; i++) {
k = '' + total_types[i];
type = oTypes[k];
if (!type) {
throw errPre + 'Unknown total_type = ' + k;
}
types.push(type);
}
limit = limit || 0;
if (isNaN(limit)) {
throw errPre + '`limit` is not a Number!';
}
limit = parseInt(limit);
// calculating running totals
var result = [],
subres = [],
nodes = {},
key = '-',
val;
var defaultNode_ = {
values: [],
count: 0,
sum: 0,
max: null,
min: null,
avg: null,
maxA: Number.MIN_VALUE,
maxB: Number.MIN_VALUE,
maxC: Number.MIN_VALUE,
minA: Number.MAX_VALUE,
minB: Number.MAX_VALUE,
minC: Number.MAX_VALUE
};
for (var i = 0; i < numbers.length; i++) {
val = numbers[i][0];
// find correct node
if (keys) { key = keys[i][0]; }
node = nodes[key] ||
JSON.parse(JSON.stringify(defaultNode_));
/**
* For findig running Max/Min
* sourse of algorithm
* https://www.geeksforgeeks.org
* /sliding-window-maximum-maximum-of-all-subarrays-of-size-k/
*/
// max
//reset first second and third largest elements
//in response to new incoming elements
if (node.maxA<val) {
node.maxC = node.maxB;
node.maxB = node.maxA;
node.maxA = val;
} else if (node.maxB<val) {
node.maxC = node.maxB;
node.maxB = val;
} else if (node.maxC<val) {
node.maxC = val;
}
// min
if (node.minA>val) {
node.minC = node.minB;
node.minB = node.minA;
node.minA = val;
} else if (node.minB>val) {
node.minC = node.minB;
node.minB = val;
} else if (node.minC>val) {
node.minC = val;
}
// if limit exceeds
if (limit !== 0 && node.count === limit) {
//if the first biggest we earlier found
//is matching from the element that
//needs to be removed from the subarray
if(node.values[0]==node.maxA) {
//reset first biggest to second and second to third
node.maxA = node.maxB;
node.maxB = node.maxC;
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if (node.values[0]==node.maxB) {
node.maxB = node.maxC;
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if (node.values[0]==node.maxC) {
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if(node.values[0]==node.minA) {
//reset first smallest to second and second to third
node.minA = node.minB;
node.minB = node.minC;
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
if (node.values[0]==node.minB) {
node.minB = node.minC;
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
if (node.values[0]==node.minC) {
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
// sum
node.sum -= node.values[0];
// delete first value
node.values.shift();
// start new counter
node.count = limit-1;
}
// add new values
node.count++;
node.values.push(val);
node.sum += val;
node.avg = node.sum/node.count;
node.max = node.maxA;
node.min = node.minA;
// remember entered values for the next loop
nodes[key] = node;
// get the result depending on
// selected total_types
subres = [];
for (var t = 0; t < types.length; t++) {
subres.push(node[types[t]]);
}
result.push(subres);
}
// console.log(JSON.stringify(nodes, null, 4));
return result;
}
其他解决方案:
怎么样:
=INDEX(VLOOKUP(ROW(A:A), FILTER(
SORTN({ROW(A:A), A:A}, 9^9, 2, 2, 1), IFNA(SORTN(ROW(A:A), 9^9, 2, A:A, 1)<
QUERY(SORTN(ROW(A:A), 9^9, 2, A:A, 1), "offset 1", ), 1)), 2, 1))
这行不通...请参阅下面的更新
更新:
=INDEX(VLOOKUP(ROW(A:A), FILTER(SORT(SORTN({ROW(A:A), A:A}, 9^9, 2, 2, 1)),
COUNTIFS(UNIQUE(A:A), ">"&UNIQUE(A:A),
SEQUENCE(COUNTUNIQUE(A:A)+1), "<="&SEQUENCE(COUNTUNIQUE(A:A)+1))=0), 2, 1))
并考虑空行:
=INDEX(IF(A:A="",,VLOOKUP(ROW(A:A),
FILTER(SORT(SORTN(FILTER({ROW(A:A), A:A}, A:A<>""), 9^9, 2, 2, 1)),
COUNTIFS(UNIQUE(FILTER(A:A, A:A<>"")), ">"&UNIQUE(FILTER(A:A, A:A<>"")),
SEQUENCE(COUNTUNIQUE(A:A)), "<="&SEQUENCE(COUNTUNIQUE(A:A)))=0), 2, 1)))
=INDEX(QUERY(SPLIT(FLATTEN(ROW(A1:A12)&"×"&
IF(ROW(A1:A12)>=TRANSPOSE(ROW(A1:A12)), TRANSPOSE(A1:A12), )), "×"),
"select max(Col2) group by Col1 label max(Col2)''"))
但要保持快速:
=INDEX(QUERY(SPLIT(FLATTEN(
SEQUENCE(MATCH(9, 1/(A:A<>"")))&"×"&IF(
SEQUENCE(MATCH(9, 1/(A:A<>"")))>=
SEQUENCE(1, MATCH(9, 1/(A:A<>""))), TRANSPOSE(
INDIRECT("A1:A"&MATCH(9, 1/(A:A<>"")))), )), "×"),
"select max(Col2) group by Col1 label max(Col2)''"))
并考虑空行:
=INDEX(IF(A:A="",, QUERY(SPLIT(FLATTEN(
SEQUENCE(MATCH(9, 1/(A:A<>"")))&"×"&IF(
SEQUENCE(MATCH(9, 1/(A:A<>"")))>=
SEQUENCE(1, MATCH(9, 1/(A:A<>""))), TRANSPOSE(
INDIRECT("A1:A"&MATCH(9, 1/(A:A<>"")))), )), "×"),
"select max(Col2) group by Col1 label max(Col2)''")))
是的,它适用于 MIN
、SUM
、AVG
和 COUNT
ofc COUNT
太过分了
我可以把这个放进运行,@Max吗?
=ArrayFormula(if(A:A="",,vlookup(row(A:A),
{if(countifs(A1:A,">"&A:A,row(A:A),"<"&row(A:A))=0,row(A:A)),A:A}
,2)))
如果中间有空白单元格,您可以使用它:
=ArrayFormula(if(A:A="",,vlookup(row(A:A),
{if((countifs(A1:A,">"&A:A,row(A:A),"<"&row(A:A))=0)*(A:A<>""),row(A:A)),A:A}
,2)))
原公式(如果非空格之间没有空格)可以简化为
=ArrayFormula(vlookup(row(A:A),
{if(countifs(A1:A,">"&A:A,row(A:A),"<"&row(A:A))=0,row(A:A)),A:A}
,2))
我有一个手动输入的号码列表
1
100
100
10
1
1000
10
1000
1
1000
100
10
我想得到 运行 max - 初始数字数组的每个子数组的最大值。我所说的子数组是指从 [A1]
到 [A2]
、从 [A1]
到 [A3]
、从 [A1]
到 [A4]
等的数字。
结果如下:
1
100
100
100
100
1000
1000
1000
1000
1000
1000
1000
可以将更多条目添加到初始号码列表中。
赏金
100 点赏金给了
这是 100500 行的速度测试:
自定义公式示例:
=INDEX(IF(A3:A="","",
runningTotal(A3:A,4)))
代码:
/**
* Get running total for the array of numbers
* by makhrov.max@gmail.com
*
* @param {array} numbers The array of numbers
* @param {number} total_types (1-dafault) sum, (2) avg, (3) min, (4) max, (5) count;
* 1-d array or number
* @param {number} limit number of last values to count next time.
* Set to 0 (defualt) to take all values
* @param {array} keys (optional) array of keys. Function will group result by keys
* @return The hex-code of cell background & font color
* @customfunction
*/
function runningTotal(numbers, total_types, limit, keys) {
// possible types to return
var oTypes = {
'1': 'sum',
'2': 'avg',
'3': 'min',
'4': 'max',
'5': 'count'
}
// checks and defaults
var errPre = ' ';
if( typeof numbers != "object" ) {
numbers = [ [numbers] ];
}
total_types = total_types || [1];
if( typeof total_types != "object" ) {
total_types = [ total_types ];
}
if( keys && typeof keys != "object" ) {
keys = [ [keys] ];
}
if (keys) {
if (numbers.length !== keys.length) {
throw errPre + 'Numbers(' +
numbers.length +
') and keys(' +
keys.length +
') are of different length'; }
}
// assign types
var types = [], type, k;
for (var i = 0; i < total_types.length; i++) {
k = '' + total_types[i];
type = oTypes[k];
if (!type) {
throw errPre + 'Unknown total_type = ' + k;
}
types.push(type);
}
limit = limit || 0;
if (isNaN(limit)) {
throw errPre + '`limit` is not a Number!';
}
limit = parseInt(limit);
// calculating running totals
var result = [],
subres = [],
nodes = {},
key = '-',
val;
var defaultNode_ = {
values: [],
count: 0,
sum: 0,
max: null,
min: null,
avg: null,
maxA: Number.MIN_VALUE,
maxB: Number.MIN_VALUE,
maxC: Number.MIN_VALUE,
minA: Number.MAX_VALUE,
minB: Number.MAX_VALUE,
minC: Number.MAX_VALUE
};
for (var i = 0; i < numbers.length; i++) {
val = numbers[i][0];
// find correct node
if (keys) { key = keys[i][0]; }
node = nodes[key] ||
JSON.parse(JSON.stringify(defaultNode_));
/**
* For findig running Max/Min
* sourse of algorithm
* https://www.geeksforgeeks.org
* /sliding-window-maximum-maximum-of-all-subarrays-of-size-k/
*/
// max
//reset first second and third largest elements
//in response to new incoming elements
if (node.maxA<val) {
node.maxC = node.maxB;
node.maxB = node.maxA;
node.maxA = val;
} else if (node.maxB<val) {
node.maxC = node.maxB;
node.maxB = val;
} else if (node.maxC<val) {
node.maxC = val;
}
// min
if (node.minA>val) {
node.minC = node.minB;
node.minB = node.minA;
node.minA = val;
} else if (node.minB>val) {
node.minC = node.minB;
node.minB = val;
} else if (node.minC>val) {
node.minC = val;
}
// if limit exceeds
if (limit !== 0 && node.count === limit) {
//if the first biggest we earlier found
//is matching from the element that
//needs to be removed from the subarray
if(node.values[0]==node.maxA) {
//reset first biggest to second and second to third
node.maxA = node.maxB;
node.maxB = node.maxC;
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if (node.values[0]==node.maxB) {
node.maxB = node.maxC;
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if (node.values[0]==node.maxC) {
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if(node.values[0]==node.minA) {
//reset first smallest to second and second to third
node.minA = node.minB;
node.minB = node.minC;
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
if (node.values[0]==node.minB) {
node.minB = node.minC;
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
if (node.values[0]==node.minC) {
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
// sum
node.sum -= node.values[0];
// delete first value
node.values.shift();
// start new counter
node.count = limit-1;
}
// add new values
node.count++;
node.values.push(val);
node.sum += val;
node.avg = node.sum/node.count;
node.max = node.maxA;
node.min = node.minA;
// remember entered values for the next loop
nodes[key] = node;
// get the result depending on
// selected total_types
subres = [];
for (var t = 0; t < types.length; t++) {
subres.push(node[types[t]]);
}
result.push(subres);
}
// console.log(JSON.stringify(nodes, null, 4));
return result;
}
其他解决方案:
怎么样:
=INDEX(VLOOKUP(ROW(A:A), FILTER(
SORTN({ROW(A:A), A:A}, 9^9, 2, 2, 1), IFNA(SORTN(ROW(A:A), 9^9, 2, A:A, 1)<
QUERY(SORTN(ROW(A:A), 9^9, 2, A:A, 1), "offset 1", ), 1)), 2, 1))
这行不通...请参阅下面的更新
更新:
=INDEX(VLOOKUP(ROW(A:A), FILTER(SORT(SORTN({ROW(A:A), A:A}, 9^9, 2, 2, 1)),
COUNTIFS(UNIQUE(A:A), ">"&UNIQUE(A:A),
SEQUENCE(COUNTUNIQUE(A:A)+1), "<="&SEQUENCE(COUNTUNIQUE(A:A)+1))=0), 2, 1))
并考虑空行:
=INDEX(IF(A:A="",,VLOOKUP(ROW(A:A),
FILTER(SORT(SORTN(FILTER({ROW(A:A), A:A}, A:A<>""), 9^9, 2, 2, 1)),
COUNTIFS(UNIQUE(FILTER(A:A, A:A<>"")), ">"&UNIQUE(FILTER(A:A, A:A<>"")),
SEQUENCE(COUNTUNIQUE(A:A)), "<="&SEQUENCE(COUNTUNIQUE(A:A)))=0), 2, 1)))
=INDEX(QUERY(SPLIT(FLATTEN(ROW(A1:A12)&"×"&
IF(ROW(A1:A12)>=TRANSPOSE(ROW(A1:A12)), TRANSPOSE(A1:A12), )), "×"),
"select max(Col2) group by Col1 label max(Col2)''"))
但要保持快速:
=INDEX(QUERY(SPLIT(FLATTEN(
SEQUENCE(MATCH(9, 1/(A:A<>"")))&"×"&IF(
SEQUENCE(MATCH(9, 1/(A:A<>"")))>=
SEQUENCE(1, MATCH(9, 1/(A:A<>""))), TRANSPOSE(
INDIRECT("A1:A"&MATCH(9, 1/(A:A<>"")))), )), "×"),
"select max(Col2) group by Col1 label max(Col2)''"))
并考虑空行:
=INDEX(IF(A:A="",, QUERY(SPLIT(FLATTEN(
SEQUENCE(MATCH(9, 1/(A:A<>"")))&"×"&IF(
SEQUENCE(MATCH(9, 1/(A:A<>"")))>=
SEQUENCE(1, MATCH(9, 1/(A:A<>""))), TRANSPOSE(
INDIRECT("A1:A"&MATCH(9, 1/(A:A<>"")))), )), "×"),
"select max(Col2) group by Col1 label max(Col2)''")))
是的,它适用于 MIN
、SUM
、AVG
和 COUNT
ofc COUNT
太过分了
我可以把这个放进运行,@Max吗?
=ArrayFormula(if(A:A="",,vlookup(row(A:A),
{if(countifs(A1:A,">"&A:A,row(A:A),"<"&row(A:A))=0,row(A:A)),A:A}
,2)))
如果中间有空白单元格,您可以使用它:
=ArrayFormula(if(A:A="",,vlookup(row(A:A),
{if((countifs(A1:A,">"&A:A,row(A:A),"<"&row(A:A))=0)*(A:A<>""),row(A:A)),A:A}
,2)))
原公式(如果非空格之间没有空格)可以简化为
=ArrayFormula(vlookup(row(A:A),
{if(countifs(A1:A,">"&A:A,row(A:A),"<"&row(A:A))=0,row(A:A)),A:A}
,2))