LINUX.ORG.RU

Где можно обращаться к предпоследнему элементу списка как List(END-1) ?

 , ,


0

2

Получить предпоследний элемент списка:

lindex {1 2 3 4} end-1

Питон:

some_list[-2]
В Перле подобное же.

Если сравниваем, то видим, что python и Перл - это кака, а tcl - конфетка. Проблемы питона: а вдруг я не имел в виду индекс с конца, а просто ошибся и неправильно вычислил индекс? А вдруг в списке всего один элемент? Правда, и tcl не выдаст ошибки, а выдаст пустую строку, но зато хотя бы есть способ _ясно_ сказать, что я имею в виду именно элемент энный с конца. Это вроде мелочь, но в tcl таких мелочей много и они хорошо складываются.

Соответственно, вопрос такой: откуда такие красивые мелочи в tcl, и где ещё подобное есть?

И вот предварительные итоги опроса

D: - знак доллара $

bar[0 .. $]

Matlab, Julia - так же как в tcl

xs[end-1]

red - особый сахар для итераторов, хотя и не совсем то же:

 first back back tail a

С++ - итераторы приближаются к желаемому, хотя не совсем то

std::prev(std::prev(std::end(some_container)))
Также есть advance, к-рый позволяет не считать на пальцах. Однако для извлечения подсписка придётся обратиться к списку дважды, или запомнить итератор в переменной. А ещё вот так: std::end(v)[-2];

Rust - примерно то же, что С++, Вот велосипед для извлечения середины списка. Итератор от конца

v.iter().rev()

Haskell - можно сделать

data Index = Begin Int | End Int
По сути это решение можно реализовать в любом ООП языке, если вместо индекса использовать объект, и ввести объект «индекс от конца» - потомок индекса. Тут возникают вопросы про то, что это не интегрировано в стандартную библиотеку. Насчёт интеграции в такую библиотеку некие слова были сказаны, но уверенного «да запросто» я не припомню.

Ada, VHDL - сахар для получения индекса последнего элемента, т.е. не то, что надо

A'Last

Антиприз достаётся Перлу и Питону, у которых для получения элемента от конца используется отрицательный индекс:

а[-2]
Этот факт не даёт выявить в рантайме такую ошибку, как ошибочно вычисленный отрицательный индекс. Антиприз мог бы получить и сам tcl, поскольку у него доступ к индексу за пределы массива возвращает пустоту. Однако в tcl этот вопрос ортогонален к вопросу получения предпоследнего элемента, а в Питоне и Перле - нет.

★★★★★

Последнее исправление: den73 (всего исправлений: 6)
Ответ на: комментарий от RazrFalcon

Не понял.

В расте 4..5 - это всегда 4..5. А в тикле end-5 зависит от того, к чему ты применишь его. Это такая вот бомбочка замедленного действия.

Почему?

Потому что нужно отдельно в явном виде измерить длину и только потом обратиться к списку за элементом. В своём GetMiddle ты скрыл это внутри.

den73 ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Даже с кастомным?

Смотря что под этим понимать.

Кто мешает реализовать её самому? Тот же [..] в Rust - это отдельный тип - std::ops::Range, и его тоже можно передавать и тд.

«можно реализовать» - хорошо, но не значит, что потом «можно пользоваться». Лучше, когда «уже сделано и можно пользоваться».

Но допустим, если бы тебе понадобилось на расте выразить значение «5-й элемент с конца». Ты смог бы? Мне кажется, раст довольно аскетичен, наследования нет. Т.е. я сомневаюсь, что получится безшовно встроить это понятие в язык так, чтобы оно было широко применимо без танцев с бубном в каждой точке применения.

den73 ★★★★★
() автор топика
Ответ на: комментарий от RazrFalcon

Длина хранится отдельно.

Не важно, как хранится. Важно, что больше букв писать.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

хотя тут наследование вряд ли помогло бы.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Смотря что под этим понимать.

Свой список можно реализовать или там провал по производительности будет катастрофический?

потом «можно пользоваться»

Почему?

наследования нет

Есть. Но при чём тут наследование?

раст довольно аскетичен

Смотря с чем сравнивать.

Но допустим, если бы тебе понадобилось на расте выразить значение «5-й элемент с конца».

В смысле? Как это должно выглядеть? Как отдельный тип?

RazrFalcon ★★★★★
()
Ответ на: комментарий от den73

На самом-то деле, это не лишний сахар, а лишний полиморфизм

Сахар. У массива как по мне должно быть свойство (если ЯП поддерживает ООП и высокоуровневый), которое возвращает количество элементов. При таком подходе ясно, что some_list[-2] это сахарок над some_list[some_list.lenght-2]

peregrine ★★★★★
()
Ответ на: комментарий от RazrFalcon

В смысле? Как это должно выглядеть? Как отдельный тип?

Я ж давал примеры: end-1 - это в принципе в тикле строка (там всё строка). Её можно записывать в переменную и передавать как параметр. Но когда ты передашь её в нужное место в команду обработки списка, она превращается в (длина этого списка)-1.

Да я не знаю, какие там сущности в Расте есть. Есть ведь типы, трейты, макросы, и не знаю что ещё.

den73 ★★★★★
() автор топика
Ответ на: комментарий от Bad_ptr

и в чём проблема накалябать такой макрос на лиспе?

Хотя бы в том, что тогда lrange будет макросом, а не функцией, а этот вариант имеет свои недостатки. Т.е. тут у лиспа не слишком большая фора.

den73 ★★★★★
() автор топика
Ответ на: комментарий от peregrine

На самом-то деле, это не лишний сахар, а лишний полиморфизм

Сахар.

Хорошо. Это и сахар, и полиморфизм, хотя полиморфизм тут довольно экзотического вида. В тикле сахар есть, полиморфизма нет. Тебе, как я понял, любой сахар не по вкусу, а я в принципе сахар люблю, но пытаюсь отличать полезный от вредного. Так вот ПММЛ, -1 - это вредный, а end-1 - полезный.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Свой список можно реализовать или там провал по производительности будет катастрофический?

Что ты хочешь делать с ним? Если он стоит сбоку, то, наверное, можно его написать на Си и проэкспортировать. Или написать на встроенных примитивах языка (тогда думаю, что будет медленнее, хотя я плохо знаю процесс компиляции тикля - там всё не так уж просто).

Если ты хочешь заменить стандартный список, то можно попробовать подменить команды работы со списком. Может быть это и сработает, хотя совсем не факт.

В любом случае, тикль на быстроту раста явно не претендует, он про другое.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Ну функцией это тоже можно сделать. А если отказаться от ненужного end-1 и просто использовать -1(ну или добавить :from-end keyword argument), то это вообще тривиально.

Bad_ptr ★★★★★
()
Последнее исправление: Bad_ptr (всего исправлений: 1)

Проблемы питона: а вдруг я не имел в виду индекс с конца, а просто ошибся и неправильно вычислил индекс? А вдруг в списке всего один элемент?

Так это твои ошибки.

Siado ★★★★★
()
Ответ на: комментарий от Siado

Нет, не мои, поскольку я на Питоне не пишу :) Попросту говоря, такое соглашение провоцирует ошибки. Язык должен помогать не делать ошибок, а Питон в данном случае помогает их делать.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от Bad_ptr

А если отказаться от ненужного end-1 и просто использовать

Вся тема как раз о ненужности -1 и о полезности end-1. Правда, ты принадлежишь к большинству, к-рое эту полезность не поняло. Ничего, я уже почти привык.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

В данном случае ошибки провоциерует именно тикль, ибо возвращать пустую строку - бред.

Уже ведь раза три написал, что это отдельный вопрос, никак не связанный с end-1. Если бы тикль был лучше спроектирован, он МОГ БЫ выдавать ошибку при выходе за границы массива, и это не помешало бы полезности индекса end-1. А Питон не может этого сделать, поскольку отрицательные индексы в нём имеют смысл.

den73 ★★★★★
() автор топика

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

тот же System Verilog UVM и прочее - это возможности платформы, но что Verilog еще и как язык не то чтобы красив а именно эффективен и лаконичен - этого не отнять

I-Love-Microsoft ★★★★★
()
Ответ на: комментарий от peregrine

Вот. При этом вредный -1 перекочевал из популярного Перла в популярный Питон, а полезный end-1 так и остался в полузабытом тикле. В этом и парадокс, и одновременно opportunity.

den73 ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Ну, настоящая красота - это женщина, дерево, облако и пр. А в технике красота - это и есть «эффективность и лаконичность».

den73 ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Излишняя гибкость, как и свобода выбора тех или иных конструкций, дающих одинаковый результат в программировании не всегда хороша.

peregrine ★★★★★
()
Ответ на: комментарий от Bad_ptr

:from-end тогда ещё более полезней

Не полезнее, но близок. Например, какую ты предлагаешь сигнатуру для subseq, чтобы можно было написать: верни мне кусок начиная с 7-го от конца и заканчивая 3-м от конца? Именно индекс как отдельный тип данных (или что это в тикле? соглашение о записи? хз) наиболее полезен, хотя он имеет и свою цену.

А его-то (и даже :from-end) в системном виде в лиспе нет. А end-1 в тикле есть.

den73 ★★★★★
() автор топика
Ответ на: комментарий от peregrine

Ну я пока не вижу засад в end-1 (т.е. они есть, но это на уровне орфографии). Максимум, при вложенных конструкциях можно ошибиться и взять end не от того списка. Но по сравнению с -1 это всё равно не так криминально выглядит.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Про Rust уже говорили и вот следующая задачка: взять все эл-ты от второго до предпоследнего, вот вариант на тикле

Ну так, это, можно же слайсы юзать

    let nums = vec![1, 2, 3, 4, 5];
    println!("{:?}", &nums[1..nums.len() - 1]); // Печатает [2, 3, 4]

AntonyRF ★★★★
()
Ответ на: комментарий от den73

Можно подумать, что значение индекса вычисляется генератором случайных чисел. Ошибка в программе подлежит отладке. А что если ячейка памяти даст сбой и 1 станет 0? От всего не защититься. Есть случаи, когда поведение индексов в питоне по дефолту именно такое как мне надо.

И это...

>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> a[len(a) - 1]
8
>>> a[len(a) - 2]
7

Слова такие есть «верификация» и «тестирование» - жаль мало кто вспоминает про них. Это как раз, чтоб не гадать и надеяться на красоту языка...

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 2)
Ответ на: комментарий от den73

Ну так-как в тикле всё есть строка, то в лиспе тоже можно передавать :end-1. А потом парсить symbol-name и т.д.

Bad_ptr ★★★★★
()
Ответ на: комментарий от Virtuos86

Специально для Вас - аналог, вот код на tсl

lrange {a b c d e} 1 end-1
Вот на rust
&nums[1..nums.len() - 1]

Сильно ли отличается по красоте\читаемости, по мне так нет

AntonyRF ★★★★
()
Последнее исправление: AntonyRF (всего исправлений: 2)
Ответ на: комментарий от AntonyRF

Сильно ли отличается по красоте\читаемости, по мне так нет

по мне так на расте получилось г-но..оно просто эстетически некрасиво

MKuznetsov ★★★★★
()
Ответ на: комментарий от AntonyRF

Если включить режим den73, то сразу можно заметить, что nums используется 2 раза, ну и 1 и -1 это неинтуитивная аналогия с «второй» и «предпоследний». P.S. я не эстет, мне нормально, просто следую духу этого треда, заданному ТС'ом.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от Virtuos86

Просто, 99% людей которые видят код на расте очень удивляются, их отталкивает непонимание синтаксических конструкций т.к. он отличается от того, что они раньше видели, особенно народ чуть ли не падает в обморок от таких вот вещей

impl<'a, T> Send for std::vec::Drain<'a, T> 
impl<'a, T: ?Sized> !Send for RwLockReadGuard<'a, T>

И это понятно, ни кто не хочет учить новые парадигмы и вообще какие-то новые вещи, хочется пользоваться тем что есть, ну может быть что бы было чуть по лучше\ по удобнее. Ни кто даже не пытается понять зачем это, просто смотрят, что это что-то не такое с чем они привыкли работать и сразу ставят диагноз - чё та херня какая-то, С++\Python\ЛюбойДругойЯП лучше так как на нём понятно как программировать.

Я уже даже не удивляюсь этому.

AntonyRF ★★★★
()
Ответ на: комментарий от Virtuos86

что nums используется 2 раза, ну и 1 и -1 это неинтуитивная аналогия с «второй» и «предпоследний».

Честно, более компактного решения я не знаю. Но если бы такие вещи надо было бы делать больше 3-х раз в проекте над которым я работаю, то я бы сделал отдельный модуль, в нём бы написал аля глобальный трейт в котором бы сделал метод с необходимым функционалом и когда бы я его подключал к модулю, то все типы, например с интератором, сразу бы получали этот метод. А там где не было бы use мой_модуль; этот функционал был бы не доступен.

AntonyRF ★★★★
()
lindex {1 2 3 4} end-1

И как это чудо работает? Я правильно предположу, что второй аргумент функции lindex — это строка (а не число, как в остальных ЯП), и эта строка парсится в рантайме?

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

да нет, ну почему это должно парситься в рантайме? end стоит в компил тайме. Если в компилтайме видишь end в вызове lindex замени его на длину массива (или вычисление длины массива) и всё.

AndreyKl ★★★★★
()
Ответ на: комментарий от AndreyKl

Щас ещё можно устроить рабзборки что такое компилятор и интерпретатор и чем отличается компилтайм от рантайма при наличии байткода и джита

Bad_ptr ★★★★★
()
Ответ на: комментарий от AndreyKl

ну почему это должно парситься в рантайме

Потому что Tcl это интерпретируемый язык, по-крайней мере по wiki. Если уж разрешили делать так

lindex {1 2 3 4} end-1
То должно быть возможно делать и так
lindex {1 2 3 4} index_from_file("file")
К тому же, в интерпретируемых языках код отдельных модулей зачастую вообще не может быть получен во время «компиляции» (что бы это не значило), потому что сами модули могут импортироваться динамически. Поэтому логично, что эта фича должна работать именно в рантайме.

Собственно, ждём ответа Tcl-истов.

Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Потому что Tcl это интерпретируемый язык, по-крайней мере по wiki.

Ааа. я упустил из виду, спасибо.

Если уж разрешили делать так

lindex {1 2 3 4} end-1

То должно быть возможно делать и так

lindex {1 2 3 4} index_from_file("file")

ну уж прямо. end-1 может и во время интерпретации разбираться так же как во время компиляции. Оно ж перегонят это поди в какой то байт код для своей tcl машины. Не парсит же оно его каждый божий раз когда функцию вызывает.

Собственно, ждём ответа Tcl-истов.

да ладно, это фантастика, их не бывает поди.

AndreyKl ★★★★★
()
Последнее исправление: AndreyKl (всего исправлений: 2)
Ответ на: комментарий от Crocodoom

Я не Tcl-ист и мой ответ - не знаю. Что я знаю - это то, что они как-то пытались ускорить. В итоге то, что в файле и то, во что оно преобразуется - это разные вещи. Ведёт оно себя как строка, но это не значит, что оно на самом деле строка. В принципе для выражения end-что-то действительно можно делать анализ во время «компиляции», как сказал AndreyKI. С другой стороны, я сталкивался с тем, что мне удавалось загрузить в тикль файлы с совершенно дикими ошибками и узнавал я об этом при запуске.

den73 ★★★★★
() автор топика
Ответ на: комментарий от I-Love-Microsoft

Ошибка в программе подлежит отладке

И эта отладка стоит денег. А язык может подстелить соломки (меньше денег) или грабель понаставить (больше денег).

den73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.