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

вот это, например, вполне до Delphi синтаксиса допилить можно.

компилятор самого D написан на D, как и стд. библиотека.

так что не нравится синтаксис? => прикрути свой собственный CTFE макросами, транслируемый в D.

anonymous
()

Раз тут все красивостями меряются, то я вот так:

#!/usr/bin/env perl
use strict;
use warnings;
use 5.010; # say

my @list = (1, 2, 3, 4, 5, "penis");
my $last = (reverse @list)[0];
say $last;

Итог:

$ ./test.pl 
penis
DELIRIUM ☆☆☆☆☆
()
Последнее исправление: DELIRIUM (всего исправлений: 1)
Ответ на: комментарий от den73

pattern matching времени компиляции на Pegged.

см. стр. 459 и onRange

это примерно то, что ты хочешь сделать.

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

в https://julialang.org посмотри как сделаны макросы, кодогенерация и «паттерн-матчинг» - у них в документации очень популярно расписано. У них вообще «нутро» языка блестяще документировано, по сравнению с прочими

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

Спасибо, я в курсе про то, что существует этот язык, но не знаю, осилю ли читать его доку. Конечно, создателю языка это вроде нужно делать, но если всё читать, то никогда ничего не напишешь. Чукча - писатель :)

Да и данная тема не про мп вообще, а про вполне конкретный синт. сахар, к-рый к МП никакого отношения не имеет. Он скорее про синтаксис языка.

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

а как в красивом Tcl изобразить разбор JSON в нативные структуры?

JSON.load('{"foo":["42 bar", 12]}')
#=> {"foo" => ["42 bar", 12]}
JSON.dump({"foo" => ["42 bar", 12]})
#=> "{\"foo\":[\"42 bar\",12]}"
avsej
()
Последнее исправление: avsej (всего исправлений: 1)
Ответ на: комментарий от avsej

а как в красивом Tcl изобразить разбор JSON в нативные структуры?

set raw_json {
  { "foo":["42 bar",12,13] ,  "baz":15 }
}

set foo [ json::many-json2dict $raw_json ] 
MKuznetsov ★★★★★
()
Ответ на: комментарий от Crocodoom

Был у нас на работе один, написал числодробилку. Внутри C++ (вычислительное ядро), а вот вся скриптота на тикле.

вероятно это был единственный выживший. и тот исчез.

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

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

ну это конечно фантазии... кстати, забавно что нашёлся тиклист.

AndreyKl ★★★★★
()

Не знаю постил ли кто, весь тред не читал, вот Red:

>> a: [1 2 3 4]
== [1 2 3 4]
>> first back back tail a
== 3
loz ★★★★★
()
Ответ на: комментарий от den73

С одним упоминанием — не думаю, надо взять два итератора для того, что придумывается.

Исходно спрашивалось про явность (end-2 вместо -2), оно есть.

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

Одиночные лайфтаймы можно мысленно опускать и не читать, а дальше все просто, если знать что такое ?Sized и !Send

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

Дак он для компилятора и иммутабельный)
Там inferior mutability рантаймовая должна быть, как минимум, а stdout так вообще за мьютексом)

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

Ты задачу то приведи. Мне трудно представить где нужно писать в один глобальный объект что-то настолько часто, что за мьютекс или RefCell его засунуть — рожа треснет.

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

Если говорить про «читать», то читать там и нечего - обычная реализация типажа для какого-то типа. Я говорил про «писать». А лайфтаймы, как правило, проставляются там, где об этом просит компилятор, и для него же.

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

Гыы, очередной иксперт, скобочки путает, зато три звезды. Нахрена писать про язык, в котором ничего не шаришь?

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

Да там весь тикль учить дня два от силы. Просто слабаки оказались.

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

my $last = $list[$#list];

Вот так бы сразу. Хотя всё равно два раза пришлось упомянуть $list. Короче, перл не айс.

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

first back back tail a

Не нравится. back back - это как на пальцах считать. Та же проблема у предложенного выше решения на итераторах С++, хотя автор и предлагал написать бенчмарки. Пример, когда это не пройдёт - end-$N, где $N - переменная.

Т.е. тут ради однократного упоминания а пришлось пойти на более значительные извращения. В тикле использование end-1 выглядит непринуждённым и не извращённым.

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

Вобще да, зареквестил фичу с отрицательными индексами, тогда будет `a/-2`.

P.S. оказывается негатавные индексы работают, просто немного не так как я думал:

>> pick tail [1 2 3 4] -2
== 3
loz ★★★★★
()
Последнее исправление: loz (всего исправлений: 1)

Пфффф. А по-моему это как раз хороший пример того, что python конфетка, а tcl кака. some_list[-2] - просто и понятно.

вдруг я не имел в виду индекс с конца

Ты что, торгуешься с компилятором?

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

some_list[-2] - просто и понятно.

«У любой сложной задачи есть простое, красивое, неправильное решение». А вообще почитай тему - несколько человек писали то же, что и ты, и я им по-разному пытался объяснить, почему я думаю именно так. Не знаю, поняли они меня или нет, но я уж расстарался и не хочу повторяться.

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

Не понял тебя, можно поподробнее? Страдает ли ред той же болезнью, что Питон и Перл (см. тему)?

ПОдвёл предварительные итоги. Если что упустил или неправильно написал - принимаю претензии :)

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

Отрицательный индекс работает, но он высчитывается не с конца а с текущего элемента, это дополнительный индекс который есть в блоках реда:

>> a: [1 2 3 4 5]
== [1 2 3 4 5]
>> a: at a 3
== [3 4 5]
>> a/-1
== 2
>> a/-2
== 1
>> a: tail a
== []
>> a/-1
== 5
>> a/-2
== 4

Поэтому в примере -2 в сочетании с `tail` дает предпоследний, примерно как твой `end-1`.

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

На самом деле это не особая функция печати, а все что работает с блоками работает начиная с текущего индеса а не с первого:

>> list: [a b c a d e]
== [a b c a d e]
>> find list 'a
== [a b c a d e]
>> find next list 'a
== [a d e]
>> length? a
== 6
>> length? next a
== 5
loz ★★★★★
()

С++ - итераторы приближаются к желаемому, хотя не совсем то std::prev(std::prev(std::end(some_container))) Также есть advance, к-рый позволяет не считать на пальцах. Однако для извлечения подсписка придётся обратиться к списку дважды, или запомнить итератор в переменной.

мож уже написали

    std::vector<int> v = {1,2,3,4,5,6,7};
    std::cout << *(v.rbegin(  ) + 1) << "\n"; // 6

anonymous
()

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

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

ну и да.. в голянге, индекс с конца можно указать только вычитанием из длины a[len(a)-1] и только положительным числом.

package main

import "fmt"

func main() {
	var a = []string{"0", "1", "2", "3", "4"}
	fmt.Println(a[-1])
	//b := -1
	//fmt.Println(a[b])
}

go build minusindex.go

# command-line-arguments ./minusindex.go:7: invalid slice index -1 (index must be non-negative)

go build minusindex.go
./minusindex

panic: runtime error: index out of range

goroutine 1 [running]: main.main() /minusindex.go:8 +0x43

anonymous
()

Итератор в конце?
Если ты про

v.rbegin()
то в ржавчике его клон это
v.iter().rev()
Если тебе нужен не итератор, а слайс, да при том со второго элемента по второй элемент с конца, то
&a[1..a.len() - 1]

Deleted
()

Смотри еще пример из учебного язычка =)

let a = [1,2,3,4,5,6,7]
let s = a[-2..0]
io.puts(s[0]) // 6

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

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

Да легко: пусть есть внешняя либа, которая генерирует случайные целые числа (стандартные питоновские рандомы нас по каким-то причинам не устроили, например из-за скорости)

import my_random_lib as rand

x = [1, 2, 3, 4, 5]
print x[rand.randint(0, 4)]

Но вот беда - в либе оказался баг и функция randint(0, 4) выдаёт целые числа неправильного диапазона.

Что будет, если randint(0, 4) иногда выдаёт число 5? Исключение IndexError, причина ошибки найдена за пару минут, багрепорт отправлен, все счастливы-довольны.

Что будет, если randint(0, 4) иногда выдаёт число -1? Программа продолжит работать, только уже некорректно. А именно - распределение результата перестанет быть равномерным. Получаем наведенную ошибку, которую хрен найдешь, и она может всплыть где угодно и когда угодно.

Какие варианты решения? Обернуть проверкой результат, возращаемый randint(0, 4) можно, но ведь для этого как раз и придумали IndexError - именно он тут должен отрабатывать. Безопасного метода at у списков нет.

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