У меня есть 3 листа (user1, user2, результат). Каждый лист имеет три столбца (A: System_ID, B: Комментарий, C: Время последнего изменения).
Код делает это:
Просто комментарий с последним измененным временем выигрывает и вставляется в результат WS.
В любом случае, моя проблема в том, что я могу сопоставлять индексы только в том случае, если оба индекса в столбце A имеют одинаковую сортировку/порядок.
Мне нужно сопоставить все записи в столбце A, даже если они имеют разные row.number или индекс строки.
Как индексировать соответствие независимо от порядка в столбце A
Sub Get_LastModified_Here()
Application.EnableEvents = False
Dim Location1 As Workbook
Set Location1 = GetWorkbook("C:\Users\HP\Desktop\User_1.xlsb")
Dim Location2 As Workbook
Set Location2 = GetWorkbook("C:\Users\HP\Desktop\User_2.xlsb")
Dim SourceCell As Range, SourceRange As Range, CurrentRange As Range
Dim rngTarget As Range
Dim strAdr As String
Dim vSource As Variant, vTarget As Variant, vCurrent As Variant
Dim i As Long
Set SourceRange = Workbooks("User_2.xlsb").Sheets("Data").Range("A2:" & "A1607")
With SourceRange
Set SourceRange = .Resize(.Rows.Count, .Columns.Count + 3)
End With
strAdr = SourceRange.Address
Set rngTarget = Workbooks("User_1.xlsb").Worksheets("Data").Range(strAdr)
Set CurrentRange = ThisWorkbook.Worksheets("Data").Range(strAdr).Offset(0, 1)
vSource = SourceRange
vTarget = rngTarget
vCurrent = CurrentRange
For i = 1 To UBound(vSource, 1)
'Match Column A
If vSource(i, 1) = vTarget(i, 1) Then
'Check max time in Column C (user1 vs user2)
If vSource(i, 3) > vTarget(i, 3) Then
'Get max comment from ((user max)) in column B (result ws)
vCurrent(i, 1) = vSource(i, 2)
ElseIf vSource(i, 3) < vTarget(i, 3) Then
vCurrent(i, 1) = vTarget(i, 2)
ElseIf vSource(i, 3) = vTarget(i, 3) Then
vCurrent(i, 1) = vSource(i, 2)
End If
End If
Next i
SourceRange = vSource
rngTarget = vTarget
CurrentRange = vCurrent
Application.EnableEvents = True
End Sub
Вот подробное объяснение проблемы (прошу прощения за буквы CAPS):
Пользователь1 Лист
У меня есть SYSTEM_ID в ## Строке 1 ##
Лист User2
У меня ТАКОЙ же SYSTEM_ID в ## Row 2 ##
Это то, что я ПОЛУЧАЮ в листе результатов
У меня ТАКОЙ же SYSTEM_ID, но в ## Строке 3 ##
Это то, что я хочу в таблице результатов
У меня ТАКОЙ же SYSTEM_ID, но в ## Строке 3 ##
Что МОГУТ делать наши коды
Получить комментарий на основе времени последнего изменения, ТОЛЬКО ЕСЛИ "ID_1" находится в ТОЙ ЖЕ СТРОКЕ #. я пробовал (не помогло)
Что наши коды НЕ МОГУТ сделать
Получите комментарий на основе времени последнего изменения, ДАЖЕ ЕСЛИ "ID_1" находится в ДРУГОЙ СТРОКЕ #. это где мне нужна помощь?
РЕДАКТИРОВАТЬ, чтобы подтвердить соответствие предположений:
Лист Пользователь1: | Идентификатор | Комментарий | Последний мод | | --- | ------- | --------| | 3 | S1 Связь3| 2 | | 2 | S1 Связь2| 8 | | 1 | S1 Связь1| 6 |
Лист Пользователь2: | Идентификатор | Комментарий | Последний мод | | --- | ------- | --------| | 1 | S2 Связь1| 3 | | 2 | S2 Связь2| 4 | | 3 | S2 Связь3| 8 |
Ожидаемый результат:
Один из вариантов — собрать набор результатов в отдельную коллекцию, а затем заполнить набор результатов по завершении. Поскольку это операция, включающая несколько поисков (проверка того, был ли уже посещен системный идентификатор), мне нравится использовать объекты словаря. Они предлагают высокопроизводительные операции поиска.
Я собираюсь опубликовать ниже очень упрощенный пример, который вы, надеюсь, сможете использовать для своих целей. В приведенном ниже коде предполагается, что столбец SystemId является уникальным ключом, который сопоставляет запись на листе 1 с записью на листе 2. Также предполагается, что каждый системный идентификатор появляется один раз на листе. Если нет, его можно настроить для поддержки этого.
Код в основном перебирает диапазон и проверяет, имеют ли строки на обоих листах совпадающий системный идентификатор. Если это так, он добавляет эту строку в словарь, используя идентификатор в качестве ключа и массив из двух элементов, содержащий комментарий и время последнего изменения.
Если они не совпадают, он сверяет каждую запись со словарем, чтобы увидеть, был ли этот идентификатор системы уже посещен (ранее на другом листе). Если это так, он сравнивает записи и сохраняет самое последнее время модификации, в противном случае оставляет его как есть.
Попробуйте разобраться с этим и дайте нам знать, если вам нужна дополнительная помощь.
Sub Tester()
Dim oDict As Object
Dim a(0 To 1)
Dim sUser1 As Worksheet
Dim sUser2 As Worksheet
Set oDict = CreateObject("Scripting.Dictionary")
Set sUser1 = Sheets("User1")
Set sUser2 = Sheets("User2")
'Here I will assume that both ranges will always
'be the same length. I'm also hardcoding in the
'needed rows. You can use whichever logic
'works best for you to determine how to capture
'all rows in both sheets
For i = 2 To 8
'Two possibilities here:
' 1. The SystemId in both sheets match and
' can be directly compared
' 2. They differ and will each be checked
' to see if they already exist in the dict.
'You can bypass this and just treat each of the
'ranges individually, but I think it would be
'slightly more performant the way I'm doing it.
'
'Also, this assumes that each SystemId will only
'appear once in each sheet, and is a true Primary Key
If sUser1.Cells(i, 1).Value = sUser2.Cells(i, 1) Then
If sUser1.Cells(i, 3).Value > sUser2.Cells(i, 3).Value Then
MergeEntryToDictionary oDict, sUser1.Cells(i, 1).Value, _
sUser1.Cells(i, 2).Value, sUser1.Cells(i, 3).Value
Else
MergeEntryToDictionary oDict, sUser2.Cells(i, 1).Value, _
sUser2.Cells(i, 2).Value, sUser2.Cells(i, 3).Value
End If
Else
'In case they don't match, check each entry against the
'dictionary to see if the systemId has already been added.
'If not, then add it. Otherwise, compare the last mod date
'of the entry to the current, and update if needed.
MergeEntryToDictionary oDict, sUser1.Cells(i, 1).Value, _
sUser1.Cells(i, 2).Value, sUser1.Cells(i, 3).Value
MergeEntryToDictionary oDict, sUser2.Cells(i, 1).Value, _
sUser2.Cells(i, 2).Value, sUser2.Cells(i, 3).Value
End If
Next i
'Below prints back to sheet
Dim k As Variant
Dim n As Long
n = 2
For Each k In oDict.keys
Sheets("result").Cells(n, 1).Value = k
Sheets("result").Cells(n, 2).Value = oDict(k)(0)
Sheets("result").Cells(n, 3).Value = oDict(k)(1)
n = n + 1
Next k
End Sub
Function MergeEntryToDictionary(ByRef oDict As Object, _
SystemId As String, _
sComment As String, _
LastModTime As Double) As Boolean
Dim a(0 To 2)
If oDict.exists(SystemId) Then
If LastModTime > oDict(SystemId)(1) Then
a(0) = sComment
a(1) = LastModTime
oDict(SystemId) = a
End If
Else
a(0) = sComment
a(1) = LastModTime
oDict.Add SystemId, a
End If
MergeEntryToDictionary = True
End Function
он отлично работает, если все первичные ключи имеют одинаковый (порядок/сортировка). Мне просто нужно сопоставить их, даже если они упорядочены по-разному «результаты сопоставления независимо от сортировки индексов?»
@zatary код, который я написал, не различает местоположение. Функция смещения используется для извлечения значений из столбцов B и C (комментарий и отметка времени). Код работает независимо от того, совпадают ли идентификаторы с одинаковым номером строки. Это не работает для вас?
Извините, к сожалению, этого не произошло, он работает точно так же, как мой код в вопросе. Если вы попробуете его на своем компьютере, он не будет работать так, как нужно. попробуйте поместить три столбца на три листа, но в столбце A поместите ("ID_1") в разные места, например, в sht user1 в строке 2, в sh user2 в строке 3 и т. д., вы обнаружите, что комментарии не будут отражаться, если все три иметь один и тот же номер строки, только тогда это работает, но если один и тот же system_id находится в разных номерах строк, это не сработает
@Zatary Я внес изменения в свой ответ. В верхней части поста я ввожу три таблицы, показывающие значения на листах user1 и user2. Затем я показываю ожидаемый результат, который соответствует результату, генерируемому моим кодом. Соответствует ли это вашим ожидаемым входным и выходным данным? Если нет, то чем он отличается?
Привет, я отредактировал вопрос в таблицах, чтобы проиллюстрировать мою проблему чуть ниже кода, спасибо за ваше терпение :) Я не мог отредактировать ответ, пожалуйста, проверьте мой отредактированный вопрос. Проще говоря, разница в том, что я спрашиваю о сопоставлении ( один и тот же уникальный system_id) на всех листах в разных строках # в столбце A [system_id не обязательно должен иметь один и тот же номер строки на всех листах, чтобы отражать последние комментарии пользователей]
Привет, есть идеи по этому вопросу? Спасибо
@Zatary Я отредактировал код, чтобы также скопировать время последнего мода в лист результатов. Я также изменил функцию, чтобы принять дату и время для метки времени. В остальном код у меня работает. Я не уверен, почему это вызывает проблемы в вашей книге. Я воспроизвел книгу, поместил идентификаторы в отдельные строки, и в каждом случае использовалась только самая новая временная метка.
От всего сердца искренне благодарю Вас за помощь! Мне просто нужно немного изменить здесь, пожалуйста, я попытался сделать различную сортировку на всех листах, в диапазоне листов user1 ("a2") = ID_1, в диапазоне листов user2 ("a3") = ID_1, в результате ("диапазон ("a4") = ID_1. Мне нужно сопоставить идентификаторы на основе их общего (значение = ID_1), а не на основе их адреса ("a2"). Смещение (0,2). Спасибо: D