Сортировка массива JavaScript со смешанными типами значений - в поисках подходящей функции сравнения - PullRequest
0 голосов
/ 19 февраля 2019

Пожалуйста, обратитесь к таблице ниже.

Моя цель - отсортировать массив JavaScript, который содержит смешанные типы данных : числа, строки, логические значения, даты и неопределенные значения.

Это НЕ естественный вид.Вместо этого мне нужно соответствовать порядку сортировки, который MS Excel использует ... как можно точнее.

Это вопрос JavaScript ES5, но данные поступают из Excel через массивв VBA.

Платформой является MS WebBrowser Control (IE11), размещенный в пользовательской форме Excel VBA.

Это довольно эзотерично, я знаю, но, надеюсь, окончательный вопрос - нет.

В разновидности JavaScript от Microsoft есть расширение языка, называемое VBArray Object , в котором есть метод, который можно использовать для преобразования переданного безопасного массива VB в обычный массив JavaScript:

function convertVBArray(safearray){return new VBArray(safearray).toArray()}    

Метод .toArray() выполняет преобразование, включая преобразования типов данных для каждого элемента.Массив VBA имеет тип Variant (теговое объединение), который поддерживает множество различных подтипов переменных данных.Метод .toArray() преобразует их в более ограниченную палитру типов данных JavaScript.

В таблице ниже показано 23 значения.Представьте их в столбце в Excel.Я заполняю вариантный массив VBA из этого столбца (который выглядит так, как вы видите в столбце Excel Displays в таблице ниже.

Следующие два столбца показывают, как данные выглядят один раз внутри массива VBA.

В следующих трех столбцах показано, как выглядят данные после преобразования в массив JavaScript с помощью convertVBArray().

Далее я использую следующую функцию сравнения для сортировки массива JavaScript:

a.sort(function (a, b) { return isNaN(a) ? isNaN(b) ? a.localeCompare(b) : 1 : isNaN(b) ? -1 : parseFloat(a) - parseFloat(b) })

... но это не работает.

Пожалуйста, обратитесь к столбцу JS sortArray() в таблице ниже. Данные представлены в порядке, возвращенном после сортировки выше.

Я ищу изменение функции сравнения , чтобы она сортировалась как можно ближе к следующему столбцу таблицы, Excel Sort ASC.

* 1048Наконец, я хотел бы также иметь возможность имитировать обратную сортировку, как показано в последнем столбце, Excel Sort DESC.

Я понимаю, что различные значения ошибок преобразуются в значения undefined в JavaScript ичто там, вероятно,ничего с этим не поделаешь.Мне нравится, что все они оказываются в нижней части отсортированного списка.


Итак, я хочу, чтобы значения из Excel Displays были отсортированы с помощью JavaScript в порядке, показанном в Excel Sort ASC.Но моя текущая функция сравнения производит неправильный порядок, найденный в JS sortArray().

Моя текущая функция сравнения не может сортироваться в необходимом порядке .

.

В следующей таблице показано, как изменяются данные и типы данных при их передаче из Excel в VBA в JavaScipt и обратно в Excel.

+-----+---------------+------------------------------+-----------------+-----------------------+----------------------+--------------+------------------------------------------------------------+-----------------------+----------------+-----------------+-----------------+
| Row | Excel Entered |     Excel Number Format      | Excel Displays  |    VBA Array Value    | VBA Array Value Type | JS Array Ndx |                       JS Array Value                       | JS Array Value typeof | JS sortArray() | Excel Sort ASC  | Excel Sort DESC |
+-----+---------------+------------------------------+-----------------+-----------------------+----------------------+--------------+------------------------------------------------------------+-----------------------+----------------+-----------------+-----------------+
|   1 | anchorage     | General                      | anchorage       | anchorage             | 8 - vbString         |            0 | anchorage                                                  | string                | -78.96         | -78.96          | #NAME?          |
|   2 | 123           | General                      | 123             | 123                   | 5 - vbDouble         |            1 | 123                                                        | number                | 123            | -1              | #N/A            |
|   3 | FALSE         | General                      | FALSE           | False                 | 11 - vbBoolean       |            2 | false                                                      | boolean               | FALSE          | 0               | #DIV/0!         |
|   4 | =qqq          | General                      | #NAME?          | Error 2029            | 10 - vbError         |            3 | undefined                                                  | undefined             | -1             | 0.60625         | TRUE            |
|   5 | 0             | 0.000_);[Red](0.000)         | 0               | 0                     | 5 - vbDouble         |            4 | 0                                                          | number                | 0              | 1               | FALSE           |
|   6 | 43514.49663   | m/d/yyyy h:mm                | 2/18/2019 11:55 | 2/18/2019 10:59:03 AM | 7 - vbDate           |            5 | Mon Feb 18 2019 11:59:09 GMT-0800 (Pacific Standard Time)  | date                  | 43514.49663    | 99.01           | zimmer          |
|   7 | =NA()         | General                      | #N/A            | Error 2042            | 10 - vbError         |            6 | undefined                                                  | undefined             | 0.60625        | 123             | Major Tom       |
|   8 | 99.01         | $#,##0.00_);[Red]($#,##0.00) | 99.01           | 99.01                 | 6 - vbCurrency       |            7 | 99.01                                                      | number                | 1              | 3/20/2017       | anchorage       |
|   9 |               | General                      |                 |                       | 0 - vbEmpty          |            8 | undefined                                                  | undefined             | 99.01          | 2/18/2019 11:55 | ABC             |
|  10 | =1/0          | General                      | #DIV/0!         | Error 2007            | 10 - vbError         |            9 | undefined                                                  | undefined             | 888.87         |                 | 888.87          |
|  11 | =""           | General                      |                 |                       | 8 - vbString         |           10 |                                                            | string                |                | $%^%$^          | $%^%$^          |
|  12 | ABC           | @                            | ABC             | ABC                   | 8 - vbString         |           11 | ABC                                                        | string                | TRUE           | 888.87          |                 |
|  13 | -78.96        | General                      | -78.96          | -78.96                | 5 - vbDouble         |           12 | -78.96                                                     | number                | 42814          | ABC             | 2/18/2019 11:55 |
|  14 | Major Tom     | @                            | Major Tom       | Major Tom             | 8 - vbString         |           13 | Major Tom                                                  | string                | $%^%$^         | anchorage       | 3/20/2017       |
|  15 | TRUE          | General                      | TRUE            | True                  | 11 - vbBoolean       |           14 | true                                                       | boolean               | ABC            | Major Tom       | 123             |
|  16 | =TODAY()-700  | m/d/yyyy                     | 3/20/2017       | 3/20/2017             | 7 - vbDate           |           15 | Mon Mar 120 2017 00:00:00 GMT-0700 (Pacific Standard Time) | date                  | anchorage      | zimmer          | 99.01           |
|  17 | zimmer        | General                      | zimmer          | zimmer                | 8 - vbString         |           16 | zimmer                                                     | string                | Major Tom      | FALSE           | 1               |
|  18 | 1             | General                      | 1               | 1                     | 5 - vbDouble         |           17 | 1                                                          | number                | zimmer         | TRUE            | 0.60625         |
|  19 |               | General                      |                 |                       | 0 - vbEmpty          |           18 | undefined                                                  | undefined             |                | #NAME?          | 0               |
|  20 | =0-1          | General                      | -1              | -1                    | 5 - vbDouble         |           19 | -1                                                         | number                |                | #N/A            | -1              |
|  21 | 0.60625       | h:mm                         | 0.60625         | 0.60625               | 5 - vbDouble         |           20 | 0.60625                                                    | number                |                | #DIV/0!         | -78.96          |
|  22 | ="888.87"     | General                      | 888.87          | 888.87                | 8 - vbString         |           21 | 888.87                                                     | string                |                |                 |                 |
|  23 | $%^%$^        | General                      | $%^%$^          | $%^%$^                | 8 - vbString         |           22 | $%^%$^                                                     | string                |                |                 |                 |
+-----+---------------+------------------------------+-----------------+-----------------------+----------------------+--------------+------------------------------------------------------------+-----------------------+----------------+-----------------+-----------------+

Вот только массив JavaScript ицелевой порядок сортировки:

+--------------+------------------------------------------------------------+-----------------------+-------------------+
| JS Array Ndx |                       JS Array Value                       | JS Array Value typeof | TARGET SORT ORDER |
+--------------+------------------------------------------------------------+-----------------------+-------------------+
|            0 | anchorage                                                  | string                | -78.96            |
|            1 | 123                                                        | number                | -1                |
|            2 | false                                                      | boolean               | 0                 |
|            3 | undefined                                                  | undefined             | 0.60625           |
|            4 | 0                                                          | number                | 1                 |
|            5 | Mon Feb 18 2019 11:59:09 GMT-0800 (Pacific Standard Time)  | date                  | 99.01             |
|            6 | undefined                                                  | undefined             | 123               |
|            7 | 99.01                                                      | number                | 3/20/2017         |
|            8 | undefined                                                  | undefined             | 2/18/2019 11:55   |
|            9 | undefined                                                  | undefined             |                   |
|           10 |                                                            | string                | $%^%$^            |
|           11 | ABC                                                        | string                | 888.87            |
|           12 | -78.96                                                     | number                | ABC               |
|           13 | Major Tom                                                  | string                | anchorage         |
|           14 | true                                                       | boolean               | Major Tom         |
|           15 | Mon Mar 120 2017 00:00:00 GMT-0700 (Pacific Standard Time) | date                  | zimmer            |
|           16 | zimmer                                                     | string                | false             |
|           17 | 1                                                          | number                | true              |
|           18 | undefined                                                  | undefined             | undefined         |
|           19 | -1                                                         | number                | undefined         |
|           20 | 0.60625                                                    | number                | undefined         |
|           21 | 888.87                                                     | string                | undefined         |
|           22 | $%^%$^                                                     | string                | undefined         |
+--------------+------------------------------------------------------------+-----------------------+-------------------+

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

Не могу сказать, что я знаком с VB, но если вы просто хотите заказать ASC и DESC, я бы

// slice on desc as to not affect asc
var asc = new VBArray(yourArray).toArray(), desc = asc.slice().reverse();
0 голосов
/ 19 февраля 2019

Немного поздно, но вот решение с использованием lodash.

var values = [
    "anchorage",
    123,
    false,
    undefined,
    0,
    new Date("Mon Feb 18 2019 11:59:09 GMT-0800 (Pacific Standard Time)"),
    undefined,
    99.01,
    undefined,
    undefined,
    "",
    "ABC",
    -78.96,
    "Major Tom",
    true,
    new Date("Mon Mar 12 2017 00:00:00 GMT-0700 (Pacific Standard Time)"),
    "zimmer",
    1,
    undefined,
    -1,
    0.60625,
    "888.87",
    "$%^%$^"
]

var typesAsc = ["number", "date", "string", "boolean", "undefined"]


var typeOfValue = function (v) { return v instanceof Date ? "date" : typeof v }

var sortAsc = function (arr) {
    return _.orderBy(arr, _.identity, "asc")
}

var sortDesc = function (arr) {
    return _.orderBy(arr, _.identity, "desc")
}

var flattenInOrder = function (groups, ordering) {
    return _(ordering).map(function (type) { return groups[type] })
                      .flatten()
                      .value()
}

var valuesByType = _.groupBy(values, typeOfValue)

var valuesAscByType = _.mapValues(valuesByType, sortAsc)
var valuesAsc = flattenInOrder(valuesAscByType, typesAsc)
console.log(valuesAsc)

var valuesDescByType = _.mapValues(valuesByType, sortDesc)
var valuesDesc = flattenInOrder(valuesDescByType, typesAsc.reverse())
console.log(valuesDesc)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
0 голосов
/ 19 февраля 2019

Я думаю, что это что-то вроде того, что вы после.

В вашем JS Array Value typeOf говорится, что date является типом date, но в обычном Javascript typeof new Date() даст вам объект, так что в вашем случаеВозможно, вы захотите изменить на date.

. То, что я сделал здесь, это создаю составную сортировку, сначала мы сортируем по typeof, если оба a & b имеют одинаковый тип, вы получаете возвратзначение 0, это если вы выполняете вторую часть составной сортировки, здесь вам гарантировано, что a & b одного типа, поэтому просто выполните соответствующую сортировку в зависимости от типа.

Ниже приведенарабочий фрагмент, вы можете запустить, чтобы увидеть результат.

var data = [
 "anchorage",
  123,
  false,
  undefined,
  0,
  new Date("Mon Feb 18 2019 11:59:09 GMT-0800"),
  undefined,
  99.01,
  undefined,
  undefined,
  "",
  "ABC",
  -78.96,
  "Major Tom",
  true,
  new Date("Mon Mar 12 2017 00:00:00 GMT-0700"),
  "zimmer",
  1,
  undefined,
  -1,
  0.60625,
  "888.87",
  "$%^%$^"    
];

//what ordering do we want our types?.
var typesort = [
  "number", "object" /*date*/, "string", "boolean", "undefined"
];

data.sort(function (a, b) {
  //first lets sort by type
  var r = typesort.indexOf(typeof a) - typesort.indexOf(typeof b);
  if (r === 0) {
    //types are the same, need compound sort
    if (typeof a === "object") return a.getTime() - b.getTime()
    else if (typeof a === "string") return a.localeCompare(b)
    else return a - b;
  }
  return r;
});

console.log(data);
...