Автор Тема: ObjPath доступ к вложенным scripting.dictionary через точку  (Прочитано 9800 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135
  • Репутация: 462
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
Эта функция позволяет получить доступ к значению или записать значение в объектах scripting.dictionary любого уровня вложенности, используя при этом простой синтаксис.
К примеру, есть объект с такой структурой:  (2D массив)
{
"a": {
"name": "vasa",
"age": "29"
},
"b": {
"name": "sasha",
"age": "30"
}
}
В нем имя sasha лежит по следующему пути: b.name, а ее возраст: b.age
Путь, это простое перечисление ключей слева направо.

Код: AutoIt [Выделить]
$name = ObjPath($object, 'b.name')
$age = ObjPath($object, 'b.age')


Видишь, в пути я использую точку для разделения и мне кажется это гораздо проще чем писать как то так:
$object.item('b').item('name')

Т.к вложенность не ограничена, то давай добавим туда страну.

Добавим город и одну улицу: x.belarus.minsk.street = 'Lenina'
Код: AutoIt [Выделить]
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')


После этого наш объект станет таким:
{
"a": {
"name": "vasa",
"age": "29"
},
"b": {
"name": "sasha",
"age": "30"
},
"x": {
"belarus": {
"minsk": {
"street": "Lenina"
}
}
}
}
Хотя раньше ветка x не существовала, она создалась.  Очень удобно.

Добавим еще город brest и район в город minsk
Код: AutoIt [Выделить]
ObjPath($object, 'x.belarus.brest.street', 'Lenina')
ObjPath($object, 'x.belarus.minsk.area', 'Centr')

Теперь объект такой:
{
"a": {
"name": "vasa",
"age": "29"
},
"b": {
"name": "sasha",
"age": "30"
},
"x": {
"belarus": {
"minsk": {
"street": "Lenina",
"area": "Centr"
},
"brest": {
"street": "Lenina"
}
}
}
}

Ну, а если точка уже занята, то нет проблем, используй любой другой символ, хоть ->
x->belarus->minsk->street

По пути можно вернуть целый объект. Просто укажи путь до него, скажем всю Беларусь можно вернуть по пути: x.belarus
Код: AutoIt [Выделить]
$ret = ObjPath($object, 'x.belarus')

Проще простого.

Вот такое вот удобное хранилище получилось. Пользуйтесь на здоровье.
Функция ObjPathПервый параметр - это объект scripting.dictionary
Второй ($path)- это путь
Третий ($value) используется для записи нового значения.
Четвертый ($delimiter) - это разделитель.
Код: AutoIt [Выделить]
Func ObjPath($object = Default, $path = Default, $value = Default, $delimiter = '.')
    If $object = Default Then
        $object = ObjCreate('Scripting.Dictionary')
        If $path = Default Then
            Return $object
        EndIf
    EndIf

    If Not IsObj($object) Then
        Return SetError(1, 'Не является объектом', '')
    EndIf

    Local Static $STR_ENTIRESPLIT = 1
    Local $get = $value = Default, $set = Not $get
    Local $item, $current = $object
    Local $split = StringSplit($path, $delimiter, $STR_ENTIRESPLIT)

    For $index = 1 To $split[0]
        $item = $split[$index]

        If $index = $split[0] And $set Then
            ;Т.к объект не добавляется через $current.item($item) = $value, то удалим старый и запишем новый
            If IsObj($value) Then
                $current.remove($item)
                $current.add($item, $value)
            Else
                $current.item($item) = $value
            EndIf
            Return SetError(@error, 0, $object)
        EndIf

        If Not IsObj($current) Then
            Return SetError(2, 'Попытка доступа не к объекту', '')
        EndIf

        If Not $current.exists($item) Then
            If $get Then
                Return SetError(3, 'Элемент не найден', '')
            Else
                $current.add($item, ObjCreate('scripting.dictionary'))
            EndIf
        EndIf

        $current = $current.item($item)
    Next

    Return $current
EndFunc   ;==>ObjPath
 



UPD: Теперь объекты можно переписывать

Русское сообщество AutoIt

ObjPath доступ к вложенным scripting.dictionary через точку
« Отправлен: Октябрь 24, 2014, 00:03:35 »

Оффлайн DarWiM [?]

  • Продвинутый
  • ***
  • Сообщений: 527
  • Репутация: 90
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.8.1
inververs
Замечательно! Осталось придумать применение :)

Оффлайн joiner [?]

  • Расмус-бродяга
  • Модератор
  • *
  • Сообщений: 2924
  • Репутация: 493
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
inververs
может я что то не понимаю, но возвращает пустую строку
Код: AutoIt [Выделить]
$object = ObjCreate('scripting.dictionary')
ConsoleWrite(VarGetType($object)&@LF)
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')
$ret = ObjPath($object, 'belarus')
ConsoleWrite(VarGetType($ret) & @LF & $ret & @LF)

Были времена, когда солнце было ярче, трава зеленее, а водка сорокоградуснее

Русское сообщество AutoIt

Re: ObjPath доступ к вложенным scripting.dictionary через точку
« Ответ #2 Отправлен: Октябрь 24, 2014, 05:21:28 »

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135

  • Автор темы
  • Репутация: 462
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
joiner  [?]
Цитировать
inverversможет я что то не понимаю, но возвращает пустую строку
Поправил. Ошибся в примере. Путь конечно же будет x.belarus.
Код: AutoIt [Выделить]
$object = ObjCreate('scripting.dictionary')
ConsoleWrite(VarGetType($object)&@LF)
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')
$ret = ObjPath($object, 'x.belarus')
ConsoleWrite(VarGetType($ret) & @LF & $ret & @LF)
 



Добавлено: Октябрь 24, 2014, 11:34:49
DarWiM  [?]
Цитировать
Замечательно! Осталось придумать применение
Я делаю проект в котором нужно хранить о машине много данных. Данные представлены в виде json.
        "car_name": "Audi A 5 Sportback 3,0 TDI DPF S-tronic quattro",
"car_gebot": 24900,
"car_brand_name": "Audi",
"car_cubic": 3000,
"car_model_name": "A 5",
"car_model_id": "31",
        "searchHistory": {
"2014\/10\/13": {
"hitsCount": 0,
"searchRequest": "....."
},
"2014\/10\/19": {
"hitsCount": 0,
"searchRequest": "....."
}
}
И с помощью этой функции я могу легко узнать, скажем, модель. Я просто напишу car_model_name, или мне нужно знать есть ли данные по поиску за 13 октября: searchHistory.2014/10/13, а если есть, то узнать количество: searchHistory.2014/10/13.hitsCount
Или я хочу добавить новую дату. Я просто пишу searchHistory.2014/10/24.hitsCount = 1 и searchHistory.2014/10/24.searchRequest = 'blabla'
И все иерархия сама создается. Удобно.
« Последнее редактирование: Октябрь 24, 2014, 11:41:36 от inververs, Причина: Объединение сообщений »

Оффлайн joiner [?]

  • Расмус-бродяга
  • Модератор
  • *
  • Сообщений: 2924
  • Репутация: 493
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
inververs  [?]
Цитировать
Поправил. Ошибся в примере. Путь конечно же будет x.belarus.
я так тоже пробовал. результат - пустая строка
работает только так
Код: AutoIt [Выделить]
$object = ObjCreate('scripting.dictionary')
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')
$ret = ObjPath($object, 'x.belarus.minsk.street')

любой другой вариант возвращает пустую строку

Русское сообщество AutoIt

Re: ObjPath доступ к вложенным scripting.dictionary через точку
« Ответ #4 Отправлен: Октябрь 24, 2014, 12:11:40 »

Оффлайн ArvenPK [?]

  • Новичок
  • *
  • Сообщений: 14
  • Репутация: 1
    • Награды
  • Версия AutoIt: 3.3.x.x
inververs  [?]
Код: AutoIt [Выделить]
$object = ObjCreate('scripting.dictionary')
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')
$ret = ObjPath($object, 'x.belarus.minsk.street')

любой другой вариант возвращает пустую строку
Любой другой вариант возвращает объект, а не строку.

Оффлайн joiner [?]

  • Расмус-бродяга
  • Модератор
  • *
  • Сообщений: 2924
  • Репутация: 493
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
да, точно.
тогда я смог получить значения только так
Код: AutoIt [Выделить]
$object = ObjCreate('scripting.dictionary')
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')

Local $arv[4] = ['x', '.belarus', '.minsk', '.street'], $value
For $n = 0 To 3
    $value &= $arv[$n]
    $ret = ObjPath($object, $value)
    If IsObj($ret) Then
        $array = $ret.Keys
        For $i = 0 To $ret.Count - 1
            ConsoleWrite($array[$i] & @LF)
        Next
    Else
        ConsoleWrite($ret & @LF)
    EndIf
Next


Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135

  • Автор темы
  • Репутация: 462
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
joiner  [?]
Цитировать
я так тоже пробовал. результат - пустая строка
Ну правильно, объект не может быть представлен в виде строки.


Добавлено: Октябрь 24, 2014, 13:53:38
Значение получите так:
Код: AutoIt [Выделить]
$ret = ObjPath($object, 'x.belarus.minsk.street')
ConsoleWrite($ret & @CRLF)
 


А, я понял, вы говорите про значения, а я подумал про значение.
Если возвращаете объект, и нужны все значения, то либо через .keys или .values либо через цикл

Код: AutoIt [Выделить]
$object = ObjCreate('scripting.dictionary')
ObjPath($object, 'x.belarus.minsk.street', 'Lenina')
ObjPath($object, 'x.belarus.minsk.area', 'Center')
$ret = ObjPath($object, 'x.belarus.minsk')
For $item In $ret
    ConsoleWrite($item & ' = ' & $ret.item($item) & @CRLF)
Next
 

Но это уже другой вопрос, не по теме.
« Последнее редактирование: Октябрь 24, 2014, 14:01:38 от inververs »

Русское сообщество AutoIt

Re: ObjPath доступ к вложенным scripting.dictionary через точку
« Ответ #7 Отправлен: Октябрь 24, 2014, 13:52:50 »

Оффлайн ArvenPK [?]

  • Новичок
  • *
  • Сообщений: 14
  • Репутация: 1
    • Награды
  • Версия AutoIt: 3.3.x.x
Я бы добавил в шапку предупреждение, что подобный код подходит только для json-подобных ассоциативных массивов, потому как принудительно приводит тип ключа к строке:
Код: AutoIt [Выделить]
$oDict = ObjCreate('Scripting.Dictionary')
ObjPath($oDict, 1, "one")
ConsoleWrite($oDict.item(1) & @LF) ; ""
ConsoleWrite($oDict.item("1") & @LF) ; "one"


Ну и раз изначальная идея была в упрощении синтаксиса, то почему бы не создавать объект прямо внутри? Например:
(нажмите для показа/скрытия)
Чтобы можно было делать так:
Код: AutoIt [Выделить]
$oDict = ObjPath() ; новый объект
$oDict = ObjPath(Default, "1.2.3.4.5", "value") ; новый заполненный объект


Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135

  • Автор темы
  • Репутация: 462
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
ArvenPK  [?]
Цитировать
потому как принудительно приводит тип ключа к строке
Это из за функции StringSplit. После нее все стало строкой.
Поправить можно так:
Код: AutoIt [Выделить]
If StringIsDigit($item) Then $item = Number($item)


Цитировать
Ну и раз изначальная идея была в упрощении синтаксиса, то почему бы не создавать объект прямо внутри?
Плюсую, хорошая идея.

Обновил первый пост.

Оффлайн ArvenPK [?]

  • Новичок
  • *
  • Сообщений: 14
  • Репутация: 1
    • Награды
  • Версия AutoIt: 3.3.x.x
Поправить можно так:
Нельзя, потому что тогда наоборот, вот такие ключи будут принудительно приводиться к числу:
Код: AutoIt [Выделить]
$oDict = ObjCreate('Scripting.Dictionary')
ObjPath($oDict, "1", "one")
ConsoleWrite($oDict.item(1) & @LF) ; "one"
ConsoleWrite($oDict.item("1") & @LF) ; ""

Это уже совсем неправильно. Текущий вариант хотя-бы соответствует формату json, где как раз ключи могут быть только строкой.

Оффлайн SyDr [?]

  • Локальный модератор
  • *
  • Сообщений: 650
  • Репутация: 157
  • Пол: Мужской
  • Сидра
    • Награды
  • Версия AutoIt: 3.3.12.0
Одна и та же функция для установки и получения значения не очень красивое решение.
Не лучше было бы:
Код: AutoIt [Выделить]
Obj_Get($Object, Const $sPath, Const $sDelim)
Obj_Set($Object, Const $sPath, Const ByRef $vValue, Const $sDelim)


И в бете же уже есть Maps, а JSON очень хорошо на них ложится (моя версия JSMN), не говоря уже о том, что работают они быстрее, чем Scripting.Dictionary.

Оффлайн joiner [?]

  • Расмус-бродяга
  • Модератор
  • *
  • Сообщений: 2924
  • Репутация: 493
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
SyDr  [?]
Цитировать
(моя версия JSMN)

пара ошибок выпадает. не хватает двух функций
MapKeys
IsMap

Оффлайн inververs [?]

  • AutoIt Гуру
  • *****
  • Сообщений: 2135

  • Автор темы
  • Репутация: 462
  • Пол: Мужской
    • Награды
  • Версия AutoIt: 3.3.12.0
ArvenPK  [?]
Цитировать
Нельзя, потому что тогда наоборот, вот такие ключи будут принудительно приводиться к числу
Удалил. Тогда не вижу вариантов как работать с ключами - числами. Оставил только строки. Тем более у scripting dictionary проблемы с  64-bit ключами
SyDr
Годно. Но то что появится Maps, не повод отказываться от scripting dictionary.
За библиотеку спасибо. И  попробуйте написать функцию MapPath.

joiner  [?]
Цитировать
пара ошибок выпадает. не хватает двух функций
они в бете. Для нового типа данных - Map.

Оффлайн SyDr [?]

  • Локальный модератор
  • *
  • Сообщений: 650
  • Репутация: 157
  • Пол: Мужской
  • Сидра
    • Награды
  • Версия AutoIt: 3.3.12.0
inververs
Да, у Scripting.Dictionary есть свои преимущества. MapPath написать не получится (нормально), потому что ссылок нет (т.е. если делать как в ObjPath, то будет дофига ненужного копирования в get).
С другой стороны, Map и так можно использовать в виде $Map.X.Belarus.Brest или $Map["X"]["Belarus"]["Brest"]. Не хватает только доступа ($Map) как с массивами.
« Последнее редактирование: Ноябрь 19, 2014, 21:46:51 от SyDr »

Русское сообщество AutoIt

Re: ObjPath доступ к вложенным scripting.dictionary через точку
« Ответ #14 Отправлен: Ноябрь 19, 2014, 17:16:53 »

 

Похожие темы

  Тема / Автор Ответов Последний ответ
4 Ответов
119476 Просмотров
Последний ответ Май 25, 2011, 09:35:07
от 1MDI1
3 Ответов
4255 Просмотров
Последний ответ Апрель 10, 2013, 11:49:48
от Renz
6 Ответов
4189 Просмотров
Последний ответ Май 17, 2013, 16:41:09
от forbrock
1 Ответов
2458 Просмотров
Последний ответ Февраль 26, 2014, 22:31:13
от alex33
18 Ответов
4055 Просмотров
Последний ответ Ноябрь 21, 2014, 22:29:46
от iwak
1 Ответов
2396 Просмотров
Последний ответ Июль 07, 2015, 22:32:58
от InnI
10 Ответов
2852 Просмотров
Последний ответ Сентябрь 27, 2015, 05:21:20
от joiner
2 Ответов
1689 Просмотров
Последний ответ Ноябрь 10, 2015, 01:07:51
от CreatoR
0 Ответов
129 Просмотров
Последний ответ Март 21, 2019, 09:22:16
от tar
6 Ответов
558 Просмотров
Последний ответ Апрель 02, 2019, 00:00:53
от CreatoR