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)
Ответ на: комментарий от AndreyKl

вполне возможно что интерпретатор умеет определять «статическое выражение» или «динамическое». В конце концов, кажется что для этого нужно только референсы попроверять. И тогда end-1 будет работать быстро, ну а read_file.. будет как будет.

внутри tcl строка «end-1» преобразуется(примерно на уровне парсера и по-требованию) в объект типа Index, и таковой остаётся пока выражение константно. А если оно ещё и внутри компилируемой сущности, то компилится в байт-код. Таким образом проигрыш в скорости сводится в минимум.

И действительно в реальных прикладах типичны константные обращения к «хвостам списков» - глянуть последний/предпоследний/заранее-известный Nn-ый с конца. Так что ввод сущности типа «end-const» в язык (систему макросов) вполне оправданно, потому как повышает читабельность без ущерба в производительность

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

Xeyes под NeWS

NeWS (обрати внимание на векторный гипертекстовый)

Path: utzoo!attcan!uunet!mcvax!ukc!eagle!icdoc!Ist!jh

From: j...@Ist.CO.UK (Jeremy Huxtable)

Newsgroups: comp.windows.news

Subject: Big brother

Message-ID: <1795@ist.Ist.CO.UK>

Date: 25 Jul 88 14:43:13 GMT

Organization: Imperial Software Technology, London, UK

Lines: 94

Try this out on your NeWS server.....

%!
% eye.ps
%
% Jeremy Huxtable
%
% "Big Brother" implementation in PostScript.

% Create an Eyeball class from the Default window class.

/Eyeball DefaultWindow
dictbegin
    /EyeX 0 def                 % Current eyeball position
    /EyeY 0 def
    /MouseEventMgr null def     % Event manager
dictend
classbegin
    /Transform {
	initmatrix initclip
	clippath pathbbox scale pop pop
	.5 .5 translate
    } def

    /ShapeFrameCanvas {
	gsave ParentCanvas setcanvas
	FrameX FrameY translate
	FrameWidth FrameHeight scale
	.5 .5 .5 0 360 arc
	.5 .5 .2 0 360 arc FrameCanvas setcanvasshape
	grestore
    } def

    /PaintFrame { } def

    /DrawFrame {
	bordercolor setcolor clippath fill
	0 0 .45 0 360 arc
	backgroundcolor setcolor fill
    } def

    /ShapeClientCanvas { } def

    /CreateClientCanvas { /ClientCanvas FrameCanvas newcanvas def } def

    /PaintClient {
	FrameCanvas setcanvas
	damagepath clipcanvas
	Transform DrawFrame clipcanvas
	EyeX EyeY 0 painteyeball
    } def

    /PaintFocus { } def

    /activate { % create event manager to watch the mouse.
	FrameCanvas setcanvas
	/MouseEventMgr [
	    MouseDragged
	    {
		begin
		    EyeX EyeY 1 painteyeball
		    XLocation YLocation 0 painteyeball
		    /EyeX XLocation store
		    /EyeY YLocation store
		    currentdict
		end
		redistributeevent
	    }
	    null % Action
	    null % Canvas
	    eventmgrinterest
	] forkeventmgr def
    } def

    /painteyeball { % x y colour =>
	setgray
	exch atan /angle exch def
	angle cos .2 mul
	angle sin .2 mul
	Transform
	.15 0 360 arc fill
    } def

classend def

% Now actually create a pair of eyes.
/eyeball framebuffer /new Eyeball send def
100 700 16 16 /reshape eyeball send
/map eyeball send
/activate eyeball send
/eyeball framebuffer /new Eyeball send def
145 705 16 16 /reshape eyeball send
/map eyeball send
/activate eyeball send
anonymous
()
Ответ на: комментарий от loz

А двусвязные консы и не могут ветвиться. Только односвязные могут. Консовость состоит в том, что несколько массивов делят общий-хвост, двусвязность - в том, что хвост знает голову. А реализованы эти консы как массив.

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

Ну это опять вариант с итератором? Т.е. окамль можно приписать туда же, куда и раст с плюсами. Нет?

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

А у тебя список или массив? Доступ по индексу для списка - O(n), для массива - O(1)

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

И получается, что этот синтаксический сахар годится только для этой задачи, или у него есть и полезные применения?)

Для массивов элементарно делается через новую функцию в большинстве языков. Да, в питоне странная реализация. Еще они там массивы зачем-то списками называют.

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

И до кучи еще как List в .NET. Только вот в математике векторы не меняют размерность) Да, ладно. Назвали, как назвали. Все равно, у всех по-разному

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

Так, ну окамль и форт остались за бортом, но в целом похоже, что тема пришла к логическому завершению. Верно я говорю или нет? Галку хочу поставить.

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

Только вот в математике векторы не меняют размерность)

При чём тут математика? В математике и переменные - константы, например.

Virtuos86 ★★★★★
()
Ответ на: Версия 2 от Crocodoom

кажется, что можно написать обёртку для всех в Data.List. потом вместо Data.List импортировать Data.ListImproved и будет весьма неплохо выглядеть. Но это надо поразбираться, конечно.

PS. Поглядел - там только take, drop, splitAt и !! и их generic версии вроде бы. Не так много, если получится что то вроде

-- data Index = Begin Int | End Int
++ data Index = Int | Begin Int | End Int

то сохраниться совместимость со старым кодом и можно предложение запилить. мелочь, но приятная. Если старый код не сломать, может и в апстрим примут, прямо в Data.List.

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

В математике и переменные - константы, например.

Ты, не поверишь, но в Haskell и по-умолчанию в F# и Rust - тоже

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

Так, ну окамль и форт остались за бортом, но в целом похоже, что тема пришла к логическому завершению. Верно я говорю или нет? Галку хочу поставить.

Да я еще смысла дискуссии не уловил)

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

В C++ и вектора меняют размерность, и переменные не константы, как и ещё в доброй сотне ЯП. А в огороде бузина, а в Киеве — батька.

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

Да ну его нафиг этот твой Си++. Уже давно перепробовали и неинтересно. Просто мне кажется странным массив или нечто ему подобное называть списком. Список это больше cons-ячейки в моем понимании. Вот и все. Но тут у всех разный бэкграунд

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

Ну в апстриме такое вряд ли нужно, но как пакет я это могу попробовать оформить, дней через 7-8. Как что-то интересное будет - кастану.

Crocodoom ★★★★★
()

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

Блин, конечно же можно еще так:

std::prev(std::end(v), 2);

поменяй плз

Или на

std::next(std::rbegin(v));

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

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

В разведку я бы с тобой не пошел.

upcFrost ★★★★★
()

Python:

List[len(List)-2]
Sahas ★★★★☆
()
Ответ на: комментарий от beastie

Эта тема про удобный синтаксис (сахар), читай тему. Первых двух страниц должно быть достаточно.

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

Модуль Index

AndreyKl, den73

https://github.com/Toucandy/Index/blob/master/Index.hs

Написал небольшой модуль, обобщающий понятие индекса списка. Кроме индексирования с начала (с помощью Int) теперь можно указывать в любую точку списка, например в конец или в середину. Новый индекс является инстансом Num, поэтому поддерживает арифметику и неявный каст с инта (то есть fromInteger), поэтому старый код не сломается, если пользоваться моими индексами. Переопределены функции (!!), take, drop, splitAt из Data.List

Использование:

λ> let x = [1..7]
λ> x !! 0
1
λ> x !! end
7
λ> x !! (end-3)
4
λ> x !! mid
4
λ> let x = "Hello World!"
λ> splitAt end x
("Hello World","!")
λ> splitAt (mid+1) x
("Hello W","orld!")
λ> splitAt (mid-1) x
("Hello"," World!")

Для повторения кода выше достаточно просто набрать ghci Index.hs

Пока это больше proof-of-concept, до реального использования его ещё пилить и пилить. Но не знаю, когда дойдут руки, поэтому выкладываю пока так.

Crocodoom ★★★★★
()
Ответ на: Модуль Index от Crocodoom

выглядит классно!

Рад что ты не забыл, спасибо что кастанул, будем пытаться пользоваться))

AndreyKl ★★★★★
()
Последнее исправление: AndreyKl (всего исправлений: 1)
Ответ на: Модуль Index от Crocodoom

Спасибо, если смогу понять, то пойму :)

den73 ★★★★★
() автор топика
Ответ на: Модуль Index от Crocodoom

объявить арифметику через аппликатив - отличная идея! Я б не догадался. Это ты где увидел такой подход?

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

Всё это я придумал сам. Мне кажется, что самое интересное в моём подходе - это оригинальное определение индекса.

Если вдуматься, то что такое индексирование списка? Это функция двух аргументов, которая принимает список, некое абстрактное место, и возвращает элемент списка, находящийся на этом месте. Эта сущность место должна определяться независимо от конкретных списков. Например понятие «центр списка» едино для всех списков, равно как и «третий элемент с начала», «второй элемент с конца».

Ну а потом встал вопрос, чем кодировать такие места (или же индексы). Обычно обходятся натуральными числами, но ими можно закодировать только индексы вида «N-й элемент с начала». Правильным ответом будет полиморфная функция forall a . [a] -> i, она отлично подходит.

Ещё думал над вариантом forall a . [a] -> a, т.е. зашиваем не позицию элемента в списке, а как бы «способ его оттуда достать». Наверное, это было бы эффективнее, но тогда становится непонятно, как такие функции, например, складывать. А индексы мы часто захотим складывать.

Сложение же двух фунций forall a . [a] -> i очевидно. Это будет функция, которая для любого списка [a] возвращает сумму функций-слагаемых, применённых к этому списку. Остальные арифм. операции аналогично. Ну а это и есть Applicative, что ж ещё.

Кстати, я этот модуль и в нашем телеграм-чате выкладывал, но особого интереса он там не вызвал. Хотя пару дельных советов дали.

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

Действительно, интересное решение. Из твоих рассуждений конечно видно что функция подходит и следует что аппликатив. Но находка удачная, и сошлось так хорошо: вроде не надо ничего с арифметикой выдумывать, а меня это прям пугало - думаю сколько писанины придётся. И надо ведь всё аккуратно... а тут - красота, да и только.

В целом, надо попользоваться, но я сейчас активно не программирую (надеюсь что ненадолго). Она (библиотечка) не должна быть медленнее стандартной и должна быть немного удобнее. Пока я не вижу там доработок особо: выглядит удобно, работает, не медленнее - а что ещё? Но надо пробовать.

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

а кто такой «ваш телеграм-чат», кстати? ЛОРовский? Или какая то хаскель группа?

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

Ну надо бы определить такие же индексы для всех остальных контейнеров: MArray, IArray, Vector и др. Пока не знаю, как лучше это сделать. Советовали Template Haskell. Либо делать тайпкласс и оставлять переопределение ф-ций на юзера.

выглядит удобно, работает, не медленнее

А точно не медленнее? Ты тестировал? Я пока нет.

а кто такой «ваш телеграм-чат»?

https://t.me/haskellru

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

Спасибо за ссылку на чат. Всё ещё думаю над ответом. Так, для справки)

AndreyKl ★★★★★
()
13 ноября 2017 г.
Ответ на: комментарий от Crocodoom

да, вот всё ещё думаю, но пока думаю, кажется надо таки

-data Index i = Index (forall a . [a] -> i)
+newtype Index i = Index (forall a . [a] -> i)


И да, ну надеется на восторженные отзывы может и не стоит, там ведь не такая большая либа пока что. Но мне идея всё ещё нравится. Выглядит удобно. Может дойдут руки потестровать и поработать ещё поглубже, я тогда отпишу тебе, но это наверное месяцев через пару, опять же...

AndreyKl ★★★★★
()
7 мая 2018 г.
Ответ на: комментарий от AndreyKl

AndreyKl

Наконец-то дошли руки нормально оформить всё в виде пакета. Пока только на гитхабе, позже думал выложить также на hackage. cabal install работает уже сейчас.

Есть документация, README.md, полиморфизм по контейнерам (поддерживаются не только списки, например Vector или Sequence)

https://github.com/Toucandy/data-index

Crocodoom ★★★★★
()

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

В Scilab тоже через знак доллара.

-->A = 1:10;

-->A(5:$-1)
 ans  =
 
    5.    6.    7.    8.    9.

А я сам зачастую машинально пишу через length() или size(). Такой вот я чудак человек.

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

Очень рад что у тебя дошли руки. Спасибо что оповестил. По моему, оформлено (документация) хорошо, грамматических ошибок я не нашёл, но я не ахти какой англичанин. Интересное наблюдение насчёт монады-ридера.

У меня всё ещё не дошли руки до посмотреть повнимательней на предмет хорошей реализации, к сожалению.

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

В целом конечно надо на хакадж по мере появления времени. Дело может и не ахти какое большое, но идея интересная. Да и просто удобно. Может быть кому то будет полезно или на мысль наведёт. Я всё ещё настроен попробовать в реальном коде. Но с тех пор я кода на хаскеле не писал. Правда надеюсь что в течении года буду писать довольно много.

AndreyKl ★★★★★
()
Последнее исправление: AndreyKl (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.