Что нового

Массивы Как функция _ArraySort() поступает с равными значениями в сортируемой колонке двумерного массива?

Oki

Продвинутый
Сообщения
452
Репутация
62
В справке отсутствует информация по теме. Тесты с различными данными привели к непредсказуемому поведению. Имеется в виду, каковы приоритеты значений в остальных колонках (если алгоритм не вообще какой-то иной).
 
Последнее редактирование:
Автор
Oki

Oki

Продвинутый
Сообщения
452
Репутация
62
Может есть примеры 2D массива, чтобы вникнуть в проблему
Любой двумерный массив, в сортируемой колонке которого есть хотя бы одна пара одинаковых значений. С точки зрения обычной сортировки одинаковые значения выглядят одинаково, поэтому в результате всё равно, какое из одинаковых значений окажется раньше, а какое - позже. Но одновременно с сортируемой колонкой переставляются и остальные колонки, в которых значения могут быть различными, а потому для них порядок важен. Логичнее всего в таких случаях такая перестановка, при которой строки с одинаковыми ключевыми (то есть сортируемыми) значениями попросту остаются в соответствии с начальным порядком (например, как это работает при расширенной сортировке в Excel), но в работе означенной функции это работает как-то иначе, причём в справке описания на этот счёт нет.

Скрипт для примера.
Код:
#include <Array.au3>

Local $avArray[20][3] = [ _
[1, 1, 7], _
[1, 2, 3], _
[2, 1, 7], _
[2, 2, 2], _
[1, 1, 3], _
[1, 2, 5], _
[1, 3, 2], _
[2, 1, 7], _
[2, 2, 5], _
[2, 3, 5], _
[3, 1, 7], _
[3, 2, 2], _
[3, 3, 3], _
[1, 1, 2], _
[2, 2, 7], _
[3, 3, 2], _
[3, 1, 5], _
[2, 2, 3], _
[2, 2, 7], _
[1, 3, 5] _
]

$iStart = InputBox("", "Input the value of $iStart", 0)
$iEnd = InputBox("", "Input the value of $iEnd", 0)
$iSubItem = InputBox("", "Input the value of $iSubItem", 2)
_ArrayDisplay($avArray, "Before")
_ArraySort($avArray, 0, $iStart, $iEnd, $iSubItem)
_ArrayDisplay($avArray, "After" )
 
Последнее редактирование:

Norm

Продвинутый
Сообщения
278
Репутация
74
У меня была похожая ситуация. Пришлось костыль мастерить.
После сортировки первого столбца, искал все отсортированнные диапазоны и сортировал следуюшие по приоритету столбцы, назначая диапазоны сортировки ( Start End ) из прервого.
Например, в первом столбце все найденные числа 2 начинвются с индакса 3 - это Start, а заканчиваются на 9 - это End.
После сортировки следующего стобца в этом диапазоне, первый столбец остаётся неизменным, и следующий уже приобритает нормальный вид.
Так проделывал со следующими диапазонами чисел.

Возможно не самый оптимальный вариант, но на тот момент имел только это.
 
  • Like
Реакции: Oki
Автор
Oki

Oki

Продвинутый
Сообщения
452
Репутация
62
Спасибо, отличный костыль! Пока что до появления других решений буду пользоваться. Когда в голове варилась мысль о повторной сортировке по другой колонке, выскочило из головы, что её можно делать не по всей высоте, а только от одной заданной строки до другой заданной строки. Конечно, это не очень удобное решение, но принципиально проблему решает. Вопрос того, чего всё-таки не хватает в справке, остаётся нерешённым. Возможно, после получения надёжного ответа и костыль можно более эффективный смастерить.
 
Последнее редактирование:

Norm

Продвинутый
Сообщения
278
Репутация
74
Тесты с различными данными привели к непредсказуемому поведению.
И всёже есть определённая закономерность.
Если сортировать один и тот-же столбец два и более раза, то можно заметить, что значения в других столбцах перемещаятся на одни и теже позоции.
Например, в соседнем (не сортируемом) столбце стоят 2, 9, 13.
После первой сортировки 9, 13, 2, а после повторной они снова стоят 2, 9, 13.
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Можно поиграться так:
Код:
#include <Array.au3>

Local $avArray[20][3] = [ _
[1, 1, 7], _
[1, 2, 3], _
[2, 1, 7], _
[2, 2, 2], _
[1, 1, 3], _
[1, 2, 5], _
[1, 3, 2], _
[2, 1, 7], _
[2, 2, 5], _
[2, 3, 5], _
[3, 1, 7], _
[3, 2, 2], _
[3, 3, 3], _
[1, 1, 2], _
[2, 2, 7], _
[3, 3, 2], _
[3, 1, 5], _
[2, 2, 3], _
[2, 2, 7], _
[1, 3, 5] _
]

$iStart=0
$iEnd=0
$iSubItem=2

; $iStart = InputBox("", "Input the value of $iStart", 0)
; $iEnd = InputBox("", "Input the value of $iEnd", 0)
; $iSubItem = InputBox("", "Input the value of $iSubItem", 2)

$iUb0=UBound($avArray,0)
$iUb=UBound($avArray)
ReDim $avArray[$iUb][$iUb0+2]
_ArrayDisplay($avArray,'Before1')
Local $Item[]
If $iEnd=0 Then $iEnd=$iUb-1
For $i=$iStart To $iEnd
  $Item[$avArray[$i][$iSubItem]]+=1
  $avArray[$i][$iUb0+1]=$avArray[$i][$iSubItem]&'_'&$Item[$avArray[$i][$iSubItem]]
Next

_ArrayDisplay($avArray,'Before2')
_ArraySort($avArray,0,$iStart,$iEnd,$iUb0+1)
_ArrayDisplay($avArray,'After1')
ReDim $avArray[$iUb][$iUb0+1]
_ArrayDisplay($avArray,'After2')

Сообщение автоматически объединено:

Или лучше так:
Код:
#include <Array.au3>

Local $avArray[25][3] = [ _
[1, 1, 7], _
[1, 2, 3], _
[2, 1, 7], _
[2, 2, 2], _
[1, 1, 3], _
[1, 2, 5], _
[1, 3, 2], _
[2, 1, 7], _
[2, 2, 5], _
[2, 3, 5], _
[3, 1, 7], _
[3, 2, 2], _
[3, 3, 3], _
[1, 1, 2], _
[2, 2, 7], _
[3, 3, 2], _
[3, 1, 5], _
[2, 2, 3], _
[2, 2, 7], _
[21, 22, 2], _
[33, 32, 2], _
[65, 43, 2], _
[87, 45, 2], _
[54, 4215, 2], _
[1, 3, 5] _
]

$iStart=0
$iEnd=0
$iSubItem=2

; $iStart = InputBox("", "Input the value of $iStart", 0)
; $iEnd = InputBox("", "Input the value of $iEnd", 0)
; $iSubItem = InputBox("", "Input the value of $iSubItem", 2)

$iUb0=UBound($avArray,0)
$iUb=UBound($avArray)
ReDim $avArray[$iUb][$iUb0+2]
_ArrayDisplay($avArray,'Before1')
Local $Item[]
If $iEnd=0 Then $iEnd=$iUb-1
For $i=$iStart To $iEnd
  $Item[$avArray[$i][$iSubItem]]+=1
  $avArray[$i][$iUb0+1]=$avArray[$i][$iSubItem]&'_'&StringFormat("%09d",$Item[$avArray[$i][$iSubItem]])
Next

_ArrayDisplay($avArray,'Before2')
_ArraySort($avArray,0,$iStart,$iEnd,$iUb0+1)
_ArrayDisplay($avArray,'After1')
ReDim $avArray[$iUb][$iUb0+1]
_ArrayDisplay($avArray,'After2')


Для больших массивов более 10.000 лучше использовать ObjCreate('System.Collections.Hashtable')
 
Последнее редактирование:

Norm

Продвинутый
Сообщения
278
Репутация
74
Дальше этого не идет
Код:
Local $Item[]
Local $Item[^ ERROR
 

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Дальше этого не идет
Вам придётся обновить версию Autoit для Map функций https://www.autoitscript.com/autoit3/docs/functions/Map Management.htm
или так без обновления:
Код:
#include <Array.au3>

Local $avArray[25][3] = [ _
[1, 1, 7], _
[1, 2, 3], _
[2, 1, 7], _
[2, 2, 2], _
[1, 1, 3], _
[1, 2, 5], _
[1, 3, 2], _
[2, 1, 7], _
[2, 2, 5], _
[2, 3, 5], _
[3, 1, 7], _
[3, 2, 2], _
[3, 3, 3], _
[1, 1, 2], _
[2, 2, 7], _
[3, 3, 2], _
[3, 1, 5], _
[2, 2, 3], _
[2, 2, 7], _
[21, 22, 2], _
[33, 32, 2], _
[65, 43, 2], _
[87, 45, 2], _
[54, 4215, 2], _
[1, 3, 5] _
]

$iStart=0
$iEnd=0
$iSubItem=2

; $iStart = InputBox("", "Input the value of $iStart", 0)
; $iEnd = InputBox("", "Input the value of $iEnd", 0)
; $iSubItem = InputBox("", "Input the value of $iSubItem", 2)

$iUb0=UBound($avArray,0)
$iUb=UBound($avArray)
ReDim $avArray[$iUb][$iUb0+2]
_ArrayDisplay($avArray,'Before1')
Local $Item=ObjCreate('System.Collections.Hashtable')
If $iEnd=0 Then $iEnd=$iUb-1
For $i=$iStart To $iEnd
  $Item($avArray[$i][$iSubItem])+=1
  $avArray[$i][$iUb0+1]=$avArray[$i][$iSubItem]&'_'&StringFormat("%09d",$Item($avArray[$i][$iSubItem]))
Next
$Item.Clear
; Local $Item[]
; If $iEnd=0 Then $iEnd=$iUb-1
; For $i=$iStart To $iEnd
;   $Item[$avArray[$i][$iSubItem]]+=1
;   $avArray[$i][$iUb0+1]=$avArray[$i][$iSubItem]&'_'&StringFormat("%09d",$Item[$avArray[$i][$iSubItem]])
; Next

_ArrayDisplay($avArray,'Before2')
_ArraySort($avArray,0,$iStart,$iEnd,$iUb0+1)
_ArrayDisplay($avArray,'After1')
ReDim $avArray[$iUb][$iUb0+1]
_ArrayDisplay($avArray,'After2')
 
Последнее редактирование:

Norm

Продвинутый
Сообщения
278
Репутация
74
Вам придётся обновить версию Autoit для Map функций
Пока нет возможности, нужно некоторые библиотеки перелопатить.
В примере же нет вызова Map-футкций :scratch:

Вариант без обновления, тоже не хочет.
Код:
$Item($avArray[$i][$iSubItem])+=1
$Item^ ERROR
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
В примере же нет вызова Map-футкций
$Item[$avArray[$i][$iSubItem]]+=1 - это и есть элемент возможностей MAP функций.
Ну нет так нет...
1. Хотя не вижу никаких проблем установить новую версию в отдельную папку и попробовать - я лично никогда не устанавливал Autoit в систему... все в портабельном виде - 5 мин. на проверку.
2. Непонятно на какой системе вы пробуете - 'System.Collections.Hashtable' - работает на многих Windows (особенно последних), если не обрезанные
3. На крайний случай можно подключить 'Scripting.Dictionary' , пример не буду выкладывать - видимо вам не сильно и нужно решение
 
Последнее редактирование:
Автор
Oki

Oki

Продвинутый
Сообщения
452
Репутация
62
И всёже есть определённая закономерность.
Закономерность и предсказуемость это немного разные вещи. Вопрос в том, как заранее знать в точности, к какому результату приводит работа функции.
Сообщение автоматически объединено:

Andrey_A

Из ответов не совсем ясно, какую цель можно преследовать предложенными методами. Например, возможно ли отсортировать двумерную таблицу по одному заданному столбцу, так что при равенстве значений приоритетность определяется другим заданным столбцом? Или для каких других целей все эти примеры и соображения?
Сообщение автоматически объединено:

В идеале хотелось бы решать ещё более общую задачу, но она слишком уж выходит за рамки этой темы, поэтому сформулирую эту задачу в новом топике.
 
Последнее редактирование:

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
Из ответов не совсем ясно, какую цель можно преследовать предложенными методами
А вы вообще проверяли мой код? Всё очевидно
На скрине
1. Оригинальный массив
2. Массив после обработки _ArraySort
3. То что я предложил - где сохраняется последовательность встретившихся значений
А далее сортируйте по любой колонке... я лишь дал пример сохранения последовательности, что и запрашивал автор темы...
sortline1.png

В идеале хотелось бы решать ещё более общую задачу, но она слишком уж выходит за рамки этой темы, поэтому сформулирую эту задачу в новом топике
Вы бы привели пример начального массива в новом топике и то что хотите получить из него - а так вообще ничего не понятно...
Методов сортировки куча - (От пузырьковой, шейкерной, расчёской, .... до сортировкой гномья) - что вам именно нужно никто не знает
 
Последнее редактирование:
Автор
Oki

Oki

Продвинутый
Сообщения
452
Репутация
62
То что я предложил - где сохраняется последовательность встретившихся значений
А можно поинтересоваться, за счёт чего гарантируется именно такая последовательность? Чтобы хотя бы понять общую идею.
Вы бы привели пример начального массива в новом топике и то что хотите получить из него - а так вообще ничего не понятно...
Методов сортировки куча - (От пузырьковой, шейкерной, расчёской, .... до сортировкой гномья) - что вам именно нужно никто не знает
Логичнее этот вопрос там и задавать. Метод сортировки вообще не важен, если он работает достаточно быстро. Даже неважно, что там в массиве, важно лишь, чтобы сравнение для сортировки можно было заменить с обычного на произвольное, которое может выдавать любая функция. То есть так, словно в любом месте кода сортировки написано _MyFunc($x, $y) вместо $x < $y.
 

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
А можно поинтересоваться, за счёт чего гарантируется именно такая последовательность?
Если посмотреть мой код, то там всё видно (_ArrayDisplay показывает все изменения):
1. К 2D массиву добавляется колонка с помощью ReDim
2. В неё вносятся данные
3. По этой колонке происходит сортировка
4. В конце она удаляется, опять же с помощью ReDim
sort2.png
 
Автор
Oki

Oki

Продвинутый
Сообщения
452
Репутация
62
Понятно теперь. Трюк, который сработает только на определённых форматах данных. Часто подобные трюки тоже использую. Но универсальностью здесь, к сожалению, не пахнет.
 

Andrey_A

Продвинутый
Сообщения
323
Репутация
68
универсальностью здесь, к сожалению, не пахнет
"Тут нет определённых типов данных" - вы имеете ввиду структуры, объекты, массивы, логический тип данных, указатели и.т.п?...
А где в начале темы было про определённые типы данных?
Вы дали пример цифрового массива, исходя из которого вышло решение.
Вы хотите, чтобы этот "трюк" работал на всём? - "Допиливайте" самостоятельно: в цикле ставьте свои условия для разных типов, вариантов.
В строковых и числовых данных мой код работает. Для 90% действий этого достаточно, а придираться к... можно бесконечно... на мой взгляд, вы сами не знаете чего хотите, либо объясняете неточно...
Ищите решение сами, чтобы "запахло" (возможно кто-то подскажет)
"Часто подобные трюки тоже использую" - если бы вы использовали такие "трюки", то не задавали бы простых вопросов про методы и последовательность, когда в коде с помощью _ArrayDisplay() всё и так ОЧЕвидно, тем более их 4 штуки в моём коде на каждом этапе изменений и итоговой реализации...
 
Последнее редактирование:

Norm

Продвинутый
Сообщения
278
Репутация
74
Закономерность и предсказуемость это немного разные вещи. Вопрос в том, как заранее знать в точности, к какому результату приводит работа функции.
Вы правы. Я хотел подвести к тому, что если закономерность есть, то её можно использовать, поняв по какому принципу она работает. Сделать это можно только переделкой __ArrayQuickSort2D из библиотеки Array, но Вы это и сами знаете.

Логичнее всего в таких случаях такая перестановка, при которой строки с одинаковыми ключевыми (то есть сортируемыми) значениями попросту остаются в соответствии с начальным порядком (например, как это работает при расширенной сортировке в Excel)
Для этого варианта предложенный Andrey_A способ , наверное, самый подходящий, если именно это должно быть на выходе, но vvvv
Например, возможно ли отсортировать двумерную таблицу по одному заданному столбцу, так что при равенстве значений приоритетность определяется другим заданным столбцом? Или для каких других целей все эти примеры и соображения?
Ответ Вы уже знаете ....
Варианты решения, а точнее приотитетнось могут быть разными, исходя из того, что нужно на выходе получить.
Именно так я сделал, как описал выше. Это можно взять за основу и направить в нужное направление.



3. На крайний случай можно подключить 'Scripting.Dictionary' , пример не буду выкладывать - видимо вам не сильно и нужно решение
Напротив, я хотел увидеть как Вы так легко сделали то же самое всего парой строк, но я не знал о каком варианте выходных данных Вы говорите.
После Вашего разъяснения могу лишь подтвердить Ваши слова. Но кто знает, возможно когда-то именно такой вариант и понадобится. Так что на заметку можно взять.
 
Автор
Oki

Oki

Продвинутый
Сообщения
452
Репутация
62
"Тут нет определённых типов данных" - вы имеете ввиду структуры, объекты, массивы, логический тип данных, указатели и.т.п?...
"Решение" под конкретный массив это чрезвычайно далеко от того, чтобы называться решением, не надо, пожалуйста, передёргивать.
"Часто подобные трюки тоже использую" - если бы вы использовали такие "трюки", то не задавали бы простых вопросов про методы и последовательность, когда в коде с помощью _ArrayDisplay() всё и так ОЧЕвидно, тем более их 4 штуки в моём коде на каждом этапе изменений и итоговой реализации...
Не надо скатываться в демагогию, которой с радостью рукоплещет только прибежавший лайкнуть эту чушь демагог-любитель.
Вы правы. Я хотел подвести к тому, что если закономерность есть, то её можно использовать, поняв по какому принципу она работает.
Ну именно потому в стартовом посте топика поднят этот вопрос. Мне именно хотелось понять, какова закономерность, но не экспериментально с вероятностью ошибки или с получением только узкой закономерности (не описывающей всего поведения), а более надёжно и полно от тех, кто знают, как это устроено в реальности, а тогда уж можно и сообразить, как разумно эксплуатировать устройство функции, которое забыли упомянуть в справке. Между прочим, мы тут исписали уже кучу строк текста и кучу кода, в котором по соврешенно непонятной причине вменялось разбираться, а ответа на поставленный вопрос в стартовом посте топика никто даже не коснулся.
Для этого варианта предложенный Andrey_A способ , наверное, самый подходящий, если именно это должно быть на выходе
Нет, его способ это всего лишь трюк, который предполагает, что данные будут устроены только таким образом, как в упрощённом примере. В большинстве случаев этот трюк не годится, хотя в определённых ситуациях, когда о данных что-то доподлинно известно, подобные трюки вполне могут упростить код (правда, не без ущерба культуре написания кода). Для практических нужд скорее подходит твой вышеизложенный костыль. Он хотя бы универсален, а не зависит от того, небольшие неотрицательные целые числа находятся в массиве или другие простые данные.
 
Последнее редактирование:
Верх