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)

Но ведь это кака!

Поддерживаю. В ЯП не должно быть слишком много синтаксического сахара.

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

Уточнил сказанное. На самом-то деле, это не лишний сахар, а лишний полиморфизм, который перекрывает естественный смысл отрицательного индекса (ошибка) сахарным (индекс от конца).

В tcl полиморфизма нет, а сахар есть.

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

Мне нравится голенг тем, что в нем нет синтаксического сахара. Т.е. все, вплоть до конвертации int в int32 происходит явно. Но это пока на сцену не выходит пустой интерфейс, но это уже совсем другая история. В языках в перегрузкой операторов, типа шарпа, например, никто не запрещает сделать свойство End, чтобы выглядело как myCollection.End[-2] которое бы возвращало индексатор, но это уже более ввсокоуровневая абстракция.

nikolnik ★★★
()
Ответ на: комментарий от evilface
std::next(std::rbegin(some_container))
std::prev(std::prev(std::end(some_container)))

Еще вариации на такую тему:

auto i = std::end(some_container);
std::advance(i, -2);

Если скучно:

auto i = std::begin(some_container);
for (; std::distance(i, std::end(some_container)) != 2; ++i)
        continue;

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

Если уже знаешь значение и оно уникально:

auto known_value{2};
auto i = std::find(std::begin(v), std::end(v), known_value);

Если знаешь значение и хочешь производительности (или гарантированно уникально только в последних двух элементах):

auto known_value{2};
auto i = std::find(std::rbegin(v), std::rend(v), known_value);

Если знаешь последнее значение и у тебя есть какой-то непонятный итератор:

auto known_value{3};
if (i == std::end(some_container))
        i = std::prev(i);
else
        while (*i != known_value)
                ++i;
i = std::prev(i);

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

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

проблемы питона, такие проблемы питона

shty ★★★★★
()

Всё херня надо так


value = llast(some_list)

value = lfirst(some_list)

или

value = some_list.last

value = some_list.first




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

Тьфу ты, я невнимательно прочёл, тогда так


value = llast(some_list,-1) //предпоследний

value = lfirst(some_list,1) //второй

или

value = some_list[some_list.last -1]

value = some_list[some_list.first,1]

.... херня какая то получилась.

так


value = some_list[listlen(some_list, -1)] //предпоследний
value = some_list[listlen(some_list,  1)] //второй

идеально

Dron ★★★★★
()

А какая практическая польза, как часто приходится брать n элемент с конца списка и при этом по какой-то причине не оформлять это отдельной функцией, которая и с отсутствующим элементом разберется и исключения половит, если надо.

А, ну да, проблемы интерпретируемых языков же.

anonymous
()

Rust

let array = [1, 2, 3, 4, 5];
let item = array.iter().rev().nth(1);


При том вернёт Some(value) если элемент есть и None, если нет.
Deleted
()

Вместо

val *= 5

В Tcl надо писать:

set val {expr $val * 5}

Такой классный язык, в котором даже присваивание нормально нельзя записать.

rupert ★★★★★
()

Каждый раз убеждаюсь, что божественный питон просто божественнен

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

some_vector.end() - 2;

Это ведь наверное итератор? А его ещё нужно «разыменовать». Смотри как можно ещё в tcl:

lrange {a b c d e} 1 end-1
Получится {b c d} Список упомянут только один раз. Можно так в плюсах?

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

val *= 5

А это часто нужно? А вот более частое засахарено как надо:

incr v 5
# то же, что v += 5
А вообще у tcl есть не только достоинства, конечно же. Но я сейчас конкретно про end. Просто обнаружил внезапно, что ни в одном другом языке больше такого не видел.

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

В питоне

[1,2,3][-1:]

itn ★★★
()

Питон:

some_list[-2]

Я всегда думал, что предпоследний - это второй (2) с конца. Перепиши пример так:

end = len(some_list) - 1 # индекс последнего элемента списка, -1 - потому что индексация идет с нуля
some_list[end - 1] <==> some_list[len(some_list) - 2] <==> some_list[-2]
так как «сахар» позволяет не указывать длину списка, ибо она вычисляется автоматически

Но если не охота разбираться в базовых понятиях, на которых посторен язык, то, конечно, это кака и бяка, и что там еще есть.

Virtuos86 ★★★★★
()

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

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

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

То есть тикль проглотит твою описку, и тебе это по нраву. Так и запишем.

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

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

Я здесь не сравниваю питон и тикль в целом. То, что тикль не возвращает ошибки - тоже плохо. Я говорю лишь о красоте этого решения и о том, что оно более правильное, сахарное и редкое.

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

Но тогда получается, что ты сейчас обыгрываешь известную проблему «magic numbers». В нормальной, не хеллоуворлдной программе никаких -1, -2 и -N не будет, а будут вычисляемые до места использования переменные типа index_of_item и так далее, либо целое выражение. Нет?

Virtuos86 ★★★★★
()

И чо? В плюсах ещё и не такого можно наколдовать.

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

помощью слова end, лучше, чем неявное -1, к-рое может с тем же успехом быть ошибкой

И вообще запретить все отрицательные числа -n. Пусть пишут negative(n)

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

естественный смысл отрицательного индекса (ошибка)

Сишка головного мозга?

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

ты имеешь в виду A'Last ? Это близко к теме, но не совсем оно: всё равно нужно дважды выписать имя массива.

Про VHDL имеешь в виду здесь A’reverse_range (N) - по сути то же, что в Ада. Т.е. это всё же не аналоги tcl.

Ещё у кого какие предложения?

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

Ну, спорить не стану, у меня другая задача - найти аналоги.

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

А вдруг в списке всего один элемент? Правда, и tcl не выдаст ошибки, а выдаст пустую строку

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

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

Смотри, как красиво:

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window id="vbox example" title="Example 3...."
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <vbox>
    <button id="yes" label="Yes"/>
    <button id="no" label="No"/>
    <button id="maybe" label="Maybe"/>
  </vbox>
</window>

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

В нормальной, не хеллоуворлдной программе никаких -1, -2 и -N не будет, а будут вычисляемые до места использования переменные типа index_of_item и так далее, либо целое выражение. Нет?

Задача «взять все эл-ты списка, кроме последнего» достаточно частая в любой программе. А отрицательные числа могут получиться в результате ошибок в расчётах, и питон этого не заметит. В общем-то, я здесь не для того, чтобы доказывать, что end-1 это лучше, чем -2, а для того, чтобы найти, где ещё такое есть.

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

Источник трудноуловимых ошибок.

С этим никто не спорит, но это отдельный вопрос (в тикле). В Питоне - не отдельный.

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

Не, мне не нужен пример XUL, мне нужен пример аналога «end-1». Или я его здесь не заметил.

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

lindex {1 2 3 4} end-1

Тред не читай, сразу отвечай =)

Про раст уже говорили? По мне так всё же понятнее без индексов.

    let buf = vec![1, 2, 3, 4];
    buf.last();
AntonyRF ★★★★
()
Ответ на: комментарий от den73

Если закрыть глаза на magic numbers, то ближайший вариант:

let b = 1;
let e = 1;

let v = vec![1, 2, 3, 4, 5];
let e = v.len() - b - e;
let v: Vec<&i32>  = v.iter().skip(b).take(e).collect();
println!("{:?}", v);

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

Или вообще без итераторов:

let b = 1;
let e = 1;

let v = vec![1, 2, 3, 4, 5];
let e = v.len() - e;
println!("{:?}", &v[b..e]);

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

Если тебя смущают константы единица, то это пишется так:

set b 1
set e 1
lrange {a b c d e} $b end-$e
Сравнивать Раст и тикль, конечно, особенно сложно, но по-моему, тикль здесь лучше выступает. Проблема та же: в Расте нужно обратиться к списку дважды. Если вместо {a b c d e} сложное выражение, то придётся создать под него переменную.

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

т.е. в Расте результат выражения диапазона не зависит от массива, к к-рому оно применяется, а в тикле оно подхватывает в слово end тот массив, к к-рому его применяют. В общем, пока полных аналогов тиклю никто не привёл.

Может это из смолтолка? Тикль вроде во многом растёт из смолтолка, а я смолтолк не знаю.

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

Лучше всех выступает питон. Но сравнивать скриптоту и системщину - бессмысленно.

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

Расте результат выражения диапазона не зависит от массива

Не понял.

в Расте нужно обратиться к списку дважды

Почему?

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

На самом деле вот исконно растовское решение:

trait GetMiddle {
    type Item;

    fn middle(&self, start: usize, end: usize) -> &[Self::Item];
}

impl<T> GetMiddle for Vec<T> {
    type Item = T;

    fn middle(&self, start: usize, end: usize) -> &[Self::Item] {
        let e = self.len() - end;
        &self[start..e]
    }
}

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    println!("{:?}", v.middle(1, 1));
}

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

Ты сделал костыль только для одного частного случая. В тикле индексы end-$e поддерживаются системно при всех операциях со списком, т.е. это особенность языка, а не особенность одной команды. Кроме того, ты можешь передавать такой индекс как параметр. Т.е. сказать моя-функция(пятый-элемент-с-конца), при этом никакого массива вообще рядом не видно. «пятый элемент с конца» - это некая самостоятельная абстракция, к-рая присутствует в тикле.

lrange, linsert, lindex, lsearch, lsort, lset - все его поддерживают.

В нём есть и другие подобные вещи, например, индексы и смещения в буфере редактора. Сдвинуться на три буквы вправо - это $выражениеИндекса+3c , и т.п.

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

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

Так в том-то и суть - это просто сахар. В языке важнее возможность самому создавать сахар/абстракции.

В тикле индексы end-$e поддерживаются системно при всех операциях со списком

Никто не мешает реализовать данные трейт для всех контейнеров.

со списком

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

это некая самостоятельная абстракция, к-рая присутствует в тикле

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

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

Это работает только в статике. Как только нам нужно динамически задавать размеры - всё превращается в js лапшу.

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