如何在工作表函数中从数组中提取子数组?

问题描述 投票:0回答:5

是否有某种方法可以在 Excel 中获取比单元格工作表函数中的起始数组更小的数组?

所以如果我有:

{23, "", 34, 46, "", "16"}

我最终会得到:

{23, 34, 46, 16}

然后我可以用其他一些函数来操纵它。

结论:如果我要做很多这样的事情,我肯定会使用 jtolle 的 UDF 梳解决方案。 PPC 使用的公式很接近,但是深入测试后,我发现它在空槽中给出错误,错过了第一个值,并且有一种更简单的方法来获取行号,所以这是我的最终解决方案:

=IFERROR(INDEX($A$1:$A$6, SMALL(IF(($A$1:$A$6<>""),ROW($A$1:$A$6)),ROW(1:6))),"")

必须以数组公式的形式输入(CTRL-SHIFT-ENTER)。如果要显示,则必须在至少与结果集一样大的区域中输入才能显示所有结果。

arrays excel worksheet-function
5个回答
10
投票

如果您只想获取数组的子集,并且您已经知道所需元素的位置,则可以将

INDEX
与数组一起用作索引参数。那就是:

=INDEX({11,22,33,44,55},{2,3,5})

返回

{22,33,55}
。但这通常不是很有用,因为你不知道位置,而且我不知道没有 UDF 的情况下获得它们的任何方法。

我对这种工作表内数组过滤所做的就是编写一个具有以下形式的UDF:

'Filters an input sequence based on a second "comb" sequence.
'Non-False-equivalent, non-error values in the comb represent the positions of elements
'to be kept.
Public Function combSeq(seqToComb, seqOfCombValues)

    'various library calls to work with 1xn or nx1 arrays or ranges as well as 1-D arrays

    'iterate the "comb" and collect positions of keeper elements

    'create a new array of the right length and copy in the keeper elements

End Function

我只发布了伪代码,因为我的实际代码都是对库函数的调用,包括收集位置和从位置复制操作。它可能会掩盖基本的想法,这是非常简单的。

您可以像这样调用这样的 UDF:

=combSeq({23, "", 34, 46, "", "16"}, {23, "", 34, 46, "", "16"} <> "")

=combSeq(Q1:Q42, SIN(Z1:Z42) > 0.5)

并使用 Excel 的普通数组机制来生成“梳子”。这是一种轻量级、Excel 友好的方式,可以从其他编程系统中看到的更标准的

filter(list-to-filter, test-function)
函数中获得很多好处。

我使用“comb”这个名字,因为“filter”通常意味着“用这个函数过滤”,而使用Excel,你必须在调用过滤函数之前应用测试函数。此外,计算一个“梳子”作为中间结果,然后用它来......呃,梳子......多个列表也很有用。


5
投票

这个网站上有一个答案:http://www.mrexcel.com/forum/showthread.php?t=112002。不过没有太多解释。

假设 A 列中有空白单元格的数据,并将其放入 B 列;将以相同的顺序检索数据,跳过空格

=INDEX(  $A$1:$A$6, 
         SMALL(  
            IF(
               ($A$2:$A$6<>""), 
               ROW($A$2:$A$6)
            ), 
         ROW()-ROW($B$1)
         )
      )

解释如下:

  • ROW()-ROW($B$1)只是一个技巧,它会给你一个递增的数字(即B1中的1,B2中的2......)
  • IF (... , ROW($A$2:$A$6) ) 是该技巧的主要部分:它构建一个 IF 条件为 true 的行号数组(请注意,IF 有没有“其他”值)
  • SMALL(..) 将返回该数组的第 X 个最小值(在我们的例子中是第 X 个非空白行的编号),其中 X 是当前单元格的行号(B1 中的 1 ...)
  • INDEX 然后将从行号转换为其值
  • 请注意,INDEXROW在实际表上方开始一行,以始终具有> 0的偏移量(INDEX不喜欢零)

2
投票

上述答案都给出了脆弱的公式,这些公式无法移动到工作表上的不同位置,并且对插入的行和列非常敏感。

这是一个不敏感的版本,可以移动到任何行:

=INDEX($A$10:$A$40, SMALL(IF(B$10:B$40,ROW(INDIRECT("1:30"))),ROW(INDIRECT("1:30"))))

在此示例中,原始数组值放置在 $A$10:$A$40 中(如果原始数据是行而不是列,则可以使用数组公式 {TRANSPOSE(originalArray)})。

B$10:B$40 列包含布尔标志(TRUE 或 FALSE),用于确定是否应在结果中保留此数组元素 (TRUE) 或不保留 (FALSE)。您可以使用任何您想要的函数填充此列。要创建 OP 中提到的测试,<>"",B$10 应填写:=A10<>""(然后向下复制到 B$40)。 A 列具有绝对列引用,B 列具有相对列引用,因此可以将公式复制到右侧的列中,从而允许您创建其他类型的属性和子数组,这些属性和子数组将由您放置的布尔测试控制在 C 列和 D 列等中

此示例将处理最多包含 30 个元素的原始数组。对于更大的数组,调整范围 $A$10:$A$40 和 B$10:B$40 (代表 30 行),并调整两次出现的“1:30”以适应。


1
投票

一个可能的工作表函数解决方案:

=INDEX(A1:A6,N(IF(1,MODE.MULT(IF(A1:A6<>"",ROW(1:6)*{1,1})))))

MODE.MULT
函数返回一个精简的索引数组,并插入
N(IF(1,.))
,以便将数组通过引用传递给
INDEX
函数。


0
投票

在二维数组的情况下怎么样?

我的数组地址是“G9:I11” 我只想获取第 1 列和第 3 列。

=DROP(REDUCE("",{1,3},LAMBDA(a,b,HSTACK(a,INDEX(G9:I11;;b))));;1)

这样您就可以从数组中取出各个列。

© www.soinside.com 2019 - 2024. All rights reserved.