Сравнить ячейку с предыдущей в том же столбце- VBA

#excel #vba #if-statement

#excel #vba #if-оператор

Вопрос:

У меня есть данные в Excel, подобные этому, один столбец:

 10/15/2021  7:59:42 AM
10/15/2021  7:59:44 AM
10/15/2021  7:59:46 AM
.
.
.
10/16/2021  7:59:42 AM
10/16/2021  7:59:48 AM
10/16/2021  7:59:49 AM
 

Я использовал этот код в VBA для создания двух столбцов: один с датой, а другой со временем:

 Sub CommandButton1_Click()
    Dim rng As Range
    Set rng = [A1]
    Set rng = Range(rng, Cells(Rows.Count, rng.Column).End(xlUp))

    rng.Texttocolumns Destination:=[B1], DataType:=xlDelimited, TextQualifier:=xlDoubleQuote, _
    ConsecutiveDelimiter:=False, Tab:=False, _
    Semicolon:=False, Comma:=False, Space:=True, Other:=False, FieldInfo:=Array(Array(1, xlMDYFormat), Array(2, xlMDYFormat), Array(3, xlGeneralFormat)), _
    TrailingMinusNumbers:=True
    
    Columns("C").Delete
    Columns("E").Delete
    Columns("D").Delete
    
End Sub
 

После этого у меня есть два столбца.
Моя цель — иметь один столбец с датой и временем, но иметь дату только в первый раз, когда она появляется.
Я сделал это с помощью Excel, используя IF и более поздний CONCAT.
Я скопировал первую строку, а для второй я использовал:

 IF(B3=B2,"",B3)
 

В результате получается пустая ячейка, я просто использую CONCAT со строкой, которая содержит время.
Я бы хотел сделать это в VBA, но я не уверен, как.

Комментарии:

1. Скорее всего, ваши даты — это не текстовые строки, а реальные даты, отформатированные для отображения так, как вы видите. TextToColumns работает со значением в ячейке, а не с форматированным отображением. Но Excel хранит даты в виде десятичного числа, где целая часть представляет количество дней с 1 января 1900 года, а десятичная часть — часть дня (или времени). Таким образом, вам нужно разделить соответственно на целочисленную и десятичную части значения.

2. Чего вы действительно хотите добиться? Чтобы исключить дублированную (идентичную) дату? Если это так, вам следует использовать одну строку кода rng.RemoveDuplicates 1 . Без TextTocolumns части…

3. У меня нет повторяющихся данных, у меня одна и та же дата, но разное время. Я разделяю их с помощью texttocolumn, поэтому я могу применить IF и получить дату только в первый раз, когда она появляется, а в другой ячейке я получаю пустую, поэтому, когда я использую CONCAT, у меня есть дата время только в первый раз, а для других ячеек у меня есть только время. Я легко делаю это с помощью if и concat, но я хотел бы сделать это с помощью VBA

4. @RonRosenfeld все в порядке с частью TextToColumns, я получаю то, что хочу, в одном столбце дата, в одном столбце время. То, что я делаю после, важно, потому что я делаю это с помощью IF и CONCAT, и я хотел бы сделать это с помощью VBA.

5. Всегда быстрее считывать два столбца в массив VBA (см. Раздел Массивы и диапазоны в VBA ), затем перебирать его, закрывая соответствующие записи; затем записать массив обратно на рабочий лист.

Ответ №1:

Пожалуйста, попробуйте следующий способ. Он обработает начальный столбец, не разбивая его по столбцам. Предполагается, что столбец, содержащий дату, равен «A: A». Это должно быть очень быстро для больших диапазонов, с использованием массивов и работы в памяти. Он вернет обработанный массив в столбце «B: B», начиная со второй строки (в первой я предположил, что заголовок должен быть):

 Sub keepFirstDateOnly_Date()
  Dim sh As Worksheet, lastR As Long, arrD, arrFin
  Dim firstD As String, i As Long, j As Long
  
  Set sh = ActiveSheet
  lastR = sh.Range("A" amp; sh.rows.count).End(xlUp).row
  arrD = sh.Range("A2:A" amp; lastR).Value2
  ReDim arrFin(1 To UBound(arrD), 1 To 1)
  For i = 1 To UBound(arrD)
     arrFin(i, 1) = Format(arrD(i, 1), "mm/dd/yyyy hh:mm:ss AM/PM")
     Do While DateSerial(Year(arrD(i   j, 1)), month(arrD(i   j, 1)), Day(arrD(i   j, 1))) = _
                              DateSerial(Year(arrD(i, 1)), month(arrD(i, 1)), Day(arrD(i, 1)))
        j = j   1: If i   j >= UBound(arrD) Then Exit Do
        arrFin(i   j, 1) = Format(TimeValue(CDate(arrD(i   j, 1))), "hh:mm:ss AM/PM")
     Loop
     i = i   j - 1: j = 0
  Next i
  sh.Range("B2").Resize(UBound(arrFin), 1).value = arrFin
End Sub
 

Это работает, только если диапазон, подлежащий обработке, отформатирован как дата, как вы указали.

Пожалуйста, протестируйте ее и отправьте отзыв.

То же самое предложение изменить «B2» на «A2», если вам нравится результат в B: B, чтобы он перезаписывал существующее содержимое A: A.

Комментарии:

1. Я тестировал, но это решение возвращает только строку, в которой у меня есть дата в первый раз, поэтому результатом после кода будет новый столбец с 4 строками, потому что у меня 4 разные даты. Но мне нужно сохранить каждую строку, а не дату в каждой строке.

2. @Ena Итак, вы хотели бы сохранить то, что показано в приведенном выше коде, но в строке они существуют изначально?

3. Итак, мои данные похожи на показанные выше, в результате мне нужно в одном столбце: 1st row: 10/15/2021 7:59:42 2nd row: 7:59:44 3rd row: 7:59:46 . . . 20th row: 10/16/2021 7:59:42 21st row: 7:59:48 22nd row: 7:59:49 То же значение строки, что и раньше, но дата отображается не каждый раз, она отображается только при первом появлении.

4. ОК. Я адаптирую ее для возврата таким образом. Но я не мог понять из вашего вопроса, что вам действительно нужно, извините…

5. Я попробовал еще раз в новом Excel, и это работает. Большое спасибо!