Страницы: 1 2 След.
RSS
Корректная сортировка (ранжирование) чисел, смешанных с текстом
 
Доброго времени суток, Планетяне!
Подскажите, пожалуйста, — как можно автоматизировать сортировку по шифрам, представляющих собой тексто-численные данные (см. скрин и пример)

В примере, числа между шифром и рангом - просто демонстрация, что я по ним сортировал.
Задача сводится к получению РАНГА или аналога, по которому можно провести корректную сортировку таблицы.

2017-03-01. Первое решение. Универсальное.
Изменено: Jack Famous - 02.03.2018 13:33:08
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Предлагаю отделить мух от котлет с помощью вспомогательных столбцов. А затем сортировать штатным инструментом, сначала по тексту,а затем по цифрам.

з.ы. для корректной сортировки чисел последний столбец надо умножить на 1, чтобы из текстового формата перевести в цифры.
Изменено: wowick - 01.03.2018 16:19:32
Если автоматизировать бардак, то получится автоматизированный бардак.
 
wowick, ну это вариант "в лоб" и только для конкретного примера. Если уж использовать доп. столбцы, то можно заменять нецифровые символы (33-47 и 58-255) пробелами, потом "сжать" и "разбить" по пробелу, получив массив цифр для доп. столбцов.
Спасибо за пример.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
и только для конкретного примера
Так поэтому и просят выложить пример, чтобы там были всевозможные варианты. А универсальных решений быть не может...
Изменено: wowick - 01.03.2018 16:29:27
Если автоматизировать бардак, то получится автоматизированный бардак.
 
Доброе время суток.
Вариант на регулярных выражениях, создать столбец для сортировки, приводя все числа внутри к одному формату 0000.
Скрытый текст
 
Цитата
wowick написал:
всевозможные варианты
и как же вы себе представляете всевозможные варианты шифров, индексов и прочего?))
Цитата
wowick написал:
универсальных решений быть не может
под конкретные задачи можно делать решение более или менее универсальным — мы всегда ищем компромиссы…

И это точно не повод убирать из моего примера вариант с первым числом в шифре — 23 (могут быть и такие шифры  :D )
Изменено: Jack Famous - 01.03.2018 16:48:55
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Андрей VG, фигасе)))) какое интересное решение))) спасибо большое! Всё работает!))
Я так понимаю, что к количеству чисел в шифре решение не привязано - верно?
Изменено: Jack Famous - 01.03.2018 16:49:58
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Цитата
Jack Famous написал:
что к количеству чисел в шифре решение не привязано
Да, правильно. Под числом подразумевается последовательность, состоящая только из цифр, количеством от одной и более.
Чуть переделал, с учётом, что вы пользуетесь умными таблицами.
Скрытый текст

Успехов.
 
Андрей VG, вот спасибо, мил человек!))
сейчас пишу UDF, вдохновлённый вашим решением (но по-своему пишу). Ваш макрос намного быстрее будет (буду использовать в комплексных макросах), а UDF применять удобно для разовых случаев (создал столбец, ввёл функцию, отсортировал по столбцу, удалил столбец)  :D
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Андрей VG, прошу прокомментировать - немного не понимаю…
Код
Public Sub makeCodeSortable()
    Const codeColIdx = 1 'номер столбца умной таблицы с шифрами
    Const numFormat = "0000" 'числовой формат для замены
     
    Dim pSheet As Worksheet, tmp As String, pLCol As ListColumn
    Dim vData As Variant, pLO As ListObject
    Dim pReg As Object, i As Long, pItem As Object
     
    Set pSheet = ActiveSheet
    Set pLO = pSheet.ListObjects(1)
    vData = pLO.ListColumns(codeColIdx).DataBodyRange.Value 'забираем в массив столбец шифров
    Set pReg = CreateObject("VBScript.RegExp")
    pReg.Global = True: pReg.Pattern = "\d+" 'отбираем числа (цифра одна или несколько, идущие подряд)
    For i = 1 To UBound(vData) 'для каждой ячейки с шифром
        tmp = pReg.Replace(vData(i, 1), "|||") 'вот тут не очень ясно (временный текст=во всём словаре заменить значение текущей ячейки на "|||"???)
        For Each pItem In pReg.Execute(vData(i, 1)) 'для каждого из найденных (в ячейке шифра) чисел
            tmp = Replace$(tmp, "|||", Format$(CLng(pItem.Value), numFormat), 1, 1) 'меняем во временном тексте "|||" на найденное число в текстовом формате с ведущими нулями (первое найденное и одно вхождение)
        Next
        vData(i, 1) = tmp 'пишем в массив готовую текстовую строку
    Next
    Set pLCol = pLO.ListColumns.Add(pLO.ListColumns.Count + 1) 'создаём столбец в конце таблицы
    pLCol.DataBodyRange.Value = vData 'выгружаем массив в созданный столбец
End Sub
проблема с 15 строкой (как мне кажется). Учитывая результат, в ней вы меняете найденные по шаблону числа на "|||", чтобы потом это "|||" заменить уже на числа в текстовом формате с ведущими нулями…
Сначала не понял, почему только первое и одно вхождение меняете, но потом стало ясно, что чисел несколько и вы их меняете по очереди (от первого и до последнего) и при следующем "прогоне" первым найденным будет уже следующее "|||", которое заменится на очередное число  :)

UPD (про 15 строку кода): так и есть [ССЫЛКА]tmp = pReg.Replace(vData(i, 1), "|||") означает, что не вся ячейка (данные массива) меняется на "|||" (как мне показалось). Это означает, что найденное по шаблону (числа), меняются на временную строку "|||", чтобы впоследствии эту строку обратно заменить на числа, но уже в нужном формате. Надо снова учить матчасть))
Если что - поправьте) спасибо большое ещё раз!!!
Изменено: Jack Famous - 01.03.2018 18:05:20
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
ГОТОВО! Выкладываю дополненный вариант кода от Андрея. Теперь можно оставить только числа через пробел и сортировать по ним.
Решил не заморачиваться с функцией, ведь так намного проще и быстрее — спасибо за науку!  :idea:
SortableCode_VG
Пока писал код, вспомнил, что этот метод "забивания нулями" для сортировки где-то уже видел (кажется, Казанский демонстрировал в какой-то теме) и даже писал, что это очень круто, однако, башка дырявая - вот и забыл  :D
Изменено: Jack Famous - 01.03.2018 19:53:50
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, Вот еще вариантик, там если "ав" меняется, то тоже учитывается и доп. столбцы не нужны
". |—|—| (|)"  -  все что слева или справа от "|" считается разделителем
Код
Function CodeConvert(mask, aCode, dlmtr As String)
Dim aMask, aVal(), x, n  As Long, m  As Long, i  As Long, j  As Long, dlmtr As String
If Left(mask, "1") = dlmtr Then mask = Right(mask, Len(mask) - 1)
If Right(mask, "1") = dlmtr Then mask = Left(mask, Len(mask) - 1)
aMask = Split(mask, dlmtr)
ReDim aVal(LBound(aCode) To UBound(aCode), 0 To UBound(aMask) + 1)
i = LBound(aCode)
For Each x In aCode
  n = 1
  For j = 0 To UBound(aMask)
    m = InStr(n, x, aMask(j), 1)
    If m > 0 Then
      If Len(x) >= n Then
        aVal(i, j) = Mid(x, n, m - n): n = m + Len(aMask(j))
        If IsNumeric(aVal(i, j)) Then aVal(i, j) = CDbl(aVal(i, j))
      End If
    End If
  Next
  If n <= Len(x) Then
    aVal(i, j) = Right(x, Len(x) - n + 1)
    If IsNumeric(aVal(i, j)) Then aVal(i, j) = CDbl(aVal(i, j))
  End If
  i = i + 1
Next
CodeConvert = aVal
End Function

Sub Test()
Dim aVal(), a(), a0() As Long, rngData As Range, i As Long, j As Long, aResult()
Set rngData = Sheets("sort").Cells(1).CurrentRegion
With rngData.Offset(1).Resize(rngData.Rows.Count - 1)
  a = .Resize(, 1).Value
  aVal = CodeConvert(". |—|—| (|)", a, "|")
  ReDim aColumn(LBound(aVal, 2) To UBound(aVal, 2))
  For i = LBound(aVal, 2) To UBound(aVal, 2)
    aColumn(i) = i
  Next
  Call SortAll(aVal, aColumn, a0)
  a = .Value: ReDim aResult(LBound(a) To UBound(a), LBound(a, 2) To UBound(a, 2))
  For i = LBound(a) To UBound(a)
    For j = LBound(a, 2) To UBound(a, 2): aResult(i, j) = a(a0(i), j): Next
  Next
  Sheets("result").Range(.Address) = aResult
End With
End Sub
Изменено: AAF - 02.03.2018 12:25:43
 
AAF, спасибо)
некорректно работает при увеличении количества чисел и изменении разделителя

может я неправильно как-то объяснил, но, разумеется меня интересует не "узкий" вариант под конкретный шаблон шифра (в таком случае можно было совсем простую функцию написать), а решение, позволяющее бОльшую часть число-текстовых данных корректно сортировать.
Изменено: Jack Famous - 02.03.2018 12:27:02
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Изменение разделителя добавил
А вот
Цитата
Jack Famous написал:
при увеличении количества чисел
не понял
Изменено: AAF - 02.03.2018 12:26:26
 
AAF, например такой шифр)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
"===|/|-| |-|-| (|)"
Такие вещи лучше не в картинках, а в тегах [code] подавать. Там моноширный шрифт и лучше видно сколько пробелов
Изменено: AAF - 02.03.2018 12:36:35
 
AAF, ну вот смотрите - мне каждый раз в код лезть, чтобы эти паттерны менять? Кроме того вообще отдельный лист нужен для результатов. Задача же не в том, чтобы отсортировать внутри кода, а получить РАНГ, по которому потом исходные данные можно отсортировать. Столбец шифра ведь лишь один из нескольких столбцов таблицы. Чтобы быстро и корректно отсортировать таблицу по шифру, я не могу придумать, как тут поможет ваше решение…

Решение от Андрея, крайне универсально и со всем этим прекрасно справляется (гляньте). Кажется мы немного о разном говорим…
Изменено: Jack Famous - 02.03.2018 12:40:32
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
А ранг только функцией надо?
Отдельный лист я сделал лишь только для примера
Изменено: AAF - 02.03.2018 12:41:18
 
AAF, исправил пост выше. Найденное решение является макросом. Нет - не обязательно функцией. Сначала я именно о ней думал, но, потестив макрос Андрея понял, что макрос намного удобнее…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Я понял... :)
Просто пример такой сделал. У меня там промежуточный массив выдает CodeConvert. Вот из него можно и ранг сделать.
Другой вопрос в том, если не только числовые значения, но текстовые участки могут меняться...?
 
AAF, ну вот я взял код Андрея, добавил возможность выводить только числа - в таком варианте сортировать можно учитывая только числа и их последовательность. А в классическом варианте, текст при сортировке будет учитываться - просто все числа нулями забиваются до одинаковой разрядности  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Да, понял, просто нужен ранг.
Я говорил о том, что если "ав" может быть и "аг", а еще чего доброго просто "а". Ну это наверно выходит за пределы задачи. Но если нет, то там тоже нужно задавать формат, типа "0000". Я просто хотел предложить сортировать вообще без ранга.... и без указания форматов. Хотя и там могут быть ограничения. Ведь все зависит от философии формирования кода. И здесь абсолютно универсального способа нет.
 
AAF, вы смотрели это?  :)
Просто вы пишете ровно то, что там реализовано и учтено. Как по мне - крайне универсально (вопрос необходимости и достаточности, как и всегда)
Цитата
AAF написал:
предложить сортировать вообще без ранга
повторю - смысл не в том, чтобы получить отсортированный диапазон, а в том, чтобы отсортировать ИСХОДНИК, находящийся в таблице)))
В примере из шапки видно, что я "выдёргиваю" числа из шифра в отдельные столбцы и сортирую по ним. Решение Андрея даёт абсолютно тот же результат, только без необходимости плодить столбцы (достаточно одного). Можно, конечно ещё автоматизировать, сортируя таблицу по временному столбцу макросом и удаляя его после этого, но мне больше так нравится - визуальный контроль не помешает))
Изменено: Jack Famous - 02.03.2018 13:12:19
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Если и то и то может меняться, то отделять перед сравнением текст от чисел. И одним патерном тут уже не отделаешься.
 
Anchoret, посмотрите пожалуйста сообщение №11 и скажите, что там не так с кодом (может я проглядел что-то)
если интересно, то предложите альтернативный вариант решения - я люблю расширять кругозор, но не всегда могу понять))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, писать еще один сортировщик, только уже по шифрам?) Я пас.
 
Цитата
Anchoret написал:
писать еще один сортировщик
вот хрен знает - то ли я объясняю не так, то ли что))))
не нужен мне сортировщик (ну то есть это необязательно). Нужно решение, чтобы можно было сортировать шифры более "корректно".
Одно решение найдено и отлично работает (и сортировки в коде вообще нет) - просто интересно, как можно по-другому было бы решить…

Ну нет так нет - что ж такого)) спасибо за внимание к теме  :)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Jack Famous, ради любопытства замерьте таймером обработку от 100к до 1кк через RegExp. Я не проверял, собственно вообще пока им не пользовался. Если будет долго, то стоит искать обходные пути.
 
Anchoret, насчёт таймера в коде не обещаю, а так, часами, постараюсь  ;)
правда у меня таких огромных данных нет, но смоделирую))
Изменено: Jack Famous - 02.03.2018 14:18:20
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
 
Anchoret, в общем, если ручками, то при таком монструозном примере Replace вызывает Overflow. Сработал только на 1к ячеек примерно…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Страницы: 1 2 След.
Наверх