日期范围的 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 将字符串更改为日期格式