日期范围的 UDF 或标准 IF 函数?
UDF or standard IF function for date range?
我正在尝试从列中的数字创建一个范围,并创建一个范围。例如,
column F:
1899
1912
1915
1918
1929
1934
1935
1936
...
因此,一旦 1934、1935、1936 序列开始,它将捕获 1934 并迭代直到差异不为 1。
这个例子的结果是:
1934 - 1936.
创建这些日期范围后,我将使用“-”分隔符的文本列来创建开始日期和结束日期列。
困难在于比较另一列并确保日期基于特定的标题。
所以:如果(标题 1 = 标题 2,(如果日期 2 - 日期 1 = 1,递增以检查日期 3 - 日期 2 = 1,否则 = 日期 1))。
我可以尝试嵌套许多 IF 语句,但这会让人讨厌,而且不知道每个标题要比较多少个日期。
迭代似乎通过在 VBA 中创建一个 sub 或 UDF 会容易得多,但我没有在此处(或其他地方)找到任何可能有用的示例。
使用 AGGREGATE function 检索第一组一日序列的开始和停止并不难。以H2:I2为标准公式,
'in H2
=INDEX(F:F,AGGREGATE(15,6,ROW(:)/((F:F-$F:$F)=1), 1))
'in I2
=INDEX(INDEX(F:F, MATCH(H2,F:F, 0)):F,AGGREGATE(15,6,ROW(:)/((INDEX(F:F, MATCH(H2,F:F, 0)+1):F-INDEX(F:F, MATCH(H2,F:F, 0)):$F)<>1), 1))
如果您想合并它们,请将第二个公式中所有对 H2 的引用替换为第一个公式。
我知道你需要一种方法来获取日期 "ranges" 而我仍然没有得到 "comparing another column" 东西
至于第一期,您可以试试这个(注释)代码:
Option Explicit
Sub main()
Dim fictitiousRng As Range, area As Range
Dim arr As Variant
Dim iCell As Long
With Worksheets("numbers") '<--| reference your worksheet (change "numbers" to your actual worksheet name)
With Intersect(.UsedRange, .Columns("F")).SpecialCells(xlCellTypeConstants, xlNumbers) '<-- reference its column "F" non blank cells with numeric data only
With .Offset(, .Parent.UsedRange.Columns.Count) '<--| reference referenced range offsetted 1 colum to the right
.FormulaR1C1 = "=""A"" & RC6" '<--| fill its content with a "fictitiuous" range address by placing an "A" in front of corresponding number in column "F"
Set fictitiousRng = Range("B1") ' set a initial range for 'fictitiousRng' not to bother for subsequent first call of 'Union()' method
For Each area In .Areas '<--| loop through referenced range areas (i.e. cells "groups")
For iCell = 2 To area.Cells.Count '<--| loop through current area cells
Set fictitiousRng = Union(fictitiousRng, Range(area.Cells(iCell, 1).value)) '<--| update 'fictitiousRng' with the cell corresponding to the current fictitious range address
Next iCell
Next area
arr = Split(Replace(Replace(Intersect(fictitiousRng, Columns(1)).Address(False, False), "A", ""), ":", " - "), ",") '<--| get the fictitious range address, remove "A"s and substitute "." with "-" and then write final "numbers" into an array
.ClearContents '<-- clear referenced range, i.e. cells with fictitious addresses
.Cells(1, 1).Resize(UBound(arr) + 1).value = Application.Transpose(arr) '<--| write array content into referenced range cells starting from its first cell
End With
End With
End With
End Sub
它将日期 "ranges" 写入同一列 "F" 日期工作表
的第一个 未使用 列
如果您不介意将公式分成几列,这里有一个关于如何提取开始和结束年份的 IF()
语句示例:
=IF(B13>1,"",IF(B14<2,IF(C12="",A13,C12),IF(ISNUMBER(C12),C12&"-"&A14,A13&"-"&A14)))
说明
B 列 - 找出年份之间的差异
C 列 - 优雅 nested IF()
公式 ;)
D 列 - Left()
4 个字符,如果长度 > 4
E 列 - Right()
4 个字符,如果长度 > 4
这样就可以了,它将获取 F 列中的单元格并在 G 列中打印输出。如果有年份范围(例如:1934-1935-1936),它将把它放在一个单一的作为字符串的单元格。
Sub range_dates()
Dim cel As Range
Dim iRow As Long, n As Long
Dim title As String, nextTitle As String
iRow = 2
n = 0
For i = 2 To 15
Set cel = Cells(i, "F")
title = Cells(i, "E").Value
nextTitle = Cells(i + 1, "E").Value
diff = Cells(i + 1, "F").Value - cel.Value
If diff = 1 And title = nextTitle Then
firstDate = cel.Value - n
n = n + 1
Else
Cells(iRow, "H").Value = cel.Value
Cells(iRow, "G").Value = title
If n > 0 Then
Cells(iRow, "H") = "'" & firstDate & " - " & cel.Value
n = 0
End If
iRow = iRow + 1
End If
Next
End Sub
我知道这段代码不是最优化的,但到目前为止,这是我必须分享的代码。随时改进它:)
编辑:我添加了标题条件并更改了输出以防止 excel 将字符串更改为日期格式
我正在尝试从列中的数字创建一个范围,并创建一个范围。例如,
column F:
1899
1912
1915
1918
1929
1934
1935
1936
...
因此,一旦 1934、1935、1936 序列开始,它将捕获 1934 并迭代直到差异不为 1。
这个例子的结果是:
1934 - 1936.
创建这些日期范围后,我将使用“-”分隔符的文本列来创建开始日期和结束日期列。
困难在于比较另一列并确保日期基于特定的标题。
所以:如果(标题 1 = 标题 2,(如果日期 2 - 日期 1 = 1,递增以检查日期 3 - 日期 2 = 1,否则 = 日期 1))。
我可以尝试嵌套许多 IF 语句,但这会让人讨厌,而且不知道每个标题要比较多少个日期。
迭代似乎通过在 VBA 中创建一个 sub 或 UDF 会容易得多,但我没有在此处(或其他地方)找到任何可能有用的示例。
使用 AGGREGATE function 检索第一组一日序列的开始和停止并不难。以H2:I2为标准公式,
'in H2
=INDEX(F:F,AGGREGATE(15,6,ROW(:)/((F:F-$F:$F)=1), 1))
'in I2
=INDEX(INDEX(F:F, MATCH(H2,F:F, 0)):F,AGGREGATE(15,6,ROW(:)/((INDEX(F:F, MATCH(H2,F:F, 0)+1):F-INDEX(F:F, MATCH(H2,F:F, 0)):$F)<>1), 1))
如果您想合并它们,请将第二个公式中所有对 H2 的引用替换为第一个公式。
我知道你需要一种方法来获取日期 "ranges" 而我仍然没有得到 "comparing another column" 东西
至于第一期,您可以试试这个(注释)代码:
Option Explicit
Sub main()
Dim fictitiousRng As Range, area As Range
Dim arr As Variant
Dim iCell As Long
With Worksheets("numbers") '<--| reference your worksheet (change "numbers" to your actual worksheet name)
With Intersect(.UsedRange, .Columns("F")).SpecialCells(xlCellTypeConstants, xlNumbers) '<-- reference its column "F" non blank cells with numeric data only
With .Offset(, .Parent.UsedRange.Columns.Count) '<--| reference referenced range offsetted 1 colum to the right
.FormulaR1C1 = "=""A"" & RC6" '<--| fill its content with a "fictitiuous" range address by placing an "A" in front of corresponding number in column "F"
Set fictitiousRng = Range("B1") ' set a initial range for 'fictitiousRng' not to bother for subsequent first call of 'Union()' method
For Each area In .Areas '<--| loop through referenced range areas (i.e. cells "groups")
For iCell = 2 To area.Cells.Count '<--| loop through current area cells
Set fictitiousRng = Union(fictitiousRng, Range(area.Cells(iCell, 1).value)) '<--| update 'fictitiousRng' with the cell corresponding to the current fictitious range address
Next iCell
Next area
arr = Split(Replace(Replace(Intersect(fictitiousRng, Columns(1)).Address(False, False), "A", ""), ":", " - "), ",") '<--| get the fictitious range address, remove "A"s and substitute "." with "-" and then write final "numbers" into an array
.ClearContents '<-- clear referenced range, i.e. cells with fictitious addresses
.Cells(1, 1).Resize(UBound(arr) + 1).value = Application.Transpose(arr) '<--| write array content into referenced range cells starting from its first cell
End With
End With
End With
End Sub
它将日期 "ranges" 写入同一列 "F" 日期工作表
的第一个 未使用 列如果您不介意将公式分成几列,这里有一个关于如何提取开始和结束年份的 IF()
语句示例:
=IF(B13>1,"",IF(B14<2,IF(C12="",A13,C12),IF(ISNUMBER(C12),C12&"-"&A14,A13&"-"&A14)))
说明
B 列 - 找出年份之间的差异
C 列 - 优雅 nested IF()
公式 ;)
D 列 - Left()
4 个字符,如果长度 > 4
E 列 - Right()
4 个字符,如果长度 > 4
这样就可以了,它将获取 F 列中的单元格并在 G 列中打印输出。如果有年份范围(例如:1934-1935-1936),它将把它放在一个单一的作为字符串的单元格。
Sub range_dates()
Dim cel As Range
Dim iRow As Long, n As Long
Dim title As String, nextTitle As String
iRow = 2
n = 0
For i = 2 To 15
Set cel = Cells(i, "F")
title = Cells(i, "E").Value
nextTitle = Cells(i + 1, "E").Value
diff = Cells(i + 1, "F").Value - cel.Value
If diff = 1 And title = nextTitle Then
firstDate = cel.Value - n
n = n + 1
Else
Cells(iRow, "H").Value = cel.Value
Cells(iRow, "G").Value = title
If n > 0 Then
Cells(iRow, "H") = "'" & firstDate & " - " & cel.Value
n = 0
End If
iRow = iRow + 1
End If
Next
End Sub
我知道这段代码不是最优化的,但到目前为止,这是我必须分享的代码。随时改进它:)
编辑:我添加了标题条件并更改了输出以防止 excel 将字符串更改为日期格式