Re[3]: Лучший синтаксис для перебора значений
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 06.04.06 04:24
Оценка: 1 (1) :))) :)
De-Bill,

DB>
DB>  (map 'vector #'* #(1 2 3 4 5) #(10 9 8 7 6)) ==> #(10 18 24 28 30)
DB>


DB>К сожалению, такого рода конструкции не выражаются хорошо на многих main-stream языках... а жаль...


Ещё можно предложить
http://foldl.com
http://foldr.com

quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re: Лучший синтаксис для перебора значений
От: Eugene Beschastnov Россия http://eugenius-nsk.livejournal.com/
Дата: 06.04.06 05:10
Оценка: 5 (1)
В Smalltalk используются следующие конструкции:

Перебор коллекции:

общий вид:
aCollection do: [ :element | "do something with element" ].

примеры:
aCollection do: [ :element | element blink ].
Посылает каждому элементу коллекции aCollection сообщение blink.

aCollection do: [ :element | anObject doSomethingWith: element ].
Посылает объекту anObject сообщение doSomethingWith: на каждый элемент коллекции aCollection. Параметром каждый раз передаётся текущий элемент коллекции.


Перебор по числам (реально требуется довольно редко):

общий вид:
aNumber1 to: aNumber2 do: [ :number | "do something with number" ].
или
(aNumber1 to: aNumber2) do: [ :number | "do something with number" ].
(с точки зрения поведения разницы нет)

пример:
1 to: 10 do: [ :i | anObject doSomethingWith: i ].



Перебор по числам с интервалом:

общий вид:
aNumber1 to: aNumber2 by: aNumber3 do: [ :number | "do something with number" ].
или
(aNumber1 to: aNumber2 by: aNumber3) do: [ :number | "do something with number" ].
(с точки зрения поведения разницы нет)

примеры:
1 to: 10 by: 3 do: [ :i | anObject doSomethingWith: i ].
выполнит
anObject doSomethingWith: 1.
anObject doSomethingWith: 4.
anObject doSomethingWith: 8.


1.4 to: 13.3 by: 4.7 do: [ :i | anObject doSomethingWith: i ].
выполнит
anObject doSomethingWith: 1.4.
anObject doSomethingWith: 6.1.
anObject doSomethingWith: 10.8.
--
Бесчастнов Евгений
Re[4]: Лучший синтаксис для перебора значений
От: Pavel Dvorkin Россия  
Дата: 06.04.06 05:25
Оценка: +2
Здравствуйте, IT, Вы писали:

IT>+1. Похоже, что именно поэтому так быстро прижился foreach в C#, гораздо чаще используется for в C++ по сравнению с while и в очень редких случаях применяется do while.


do while применяется так редко не поэтому, а потому что ситуации, когда необходимо выполнить тело цикла один раз обязательно, встречаются намного реже, чем ситуации, когда это не требуется.
for используеться чаще, чем while просто потому, что с for мы обычно ассоциируем последовательный перебор (0,1,2..) , а c while — произвольный итерационный процесс. Хотя это и неверно, но мы так подсознательно считаем. Есть у нас такие абстракции — for и while. А последовательный перебор встречается чаще.
With best regards
Pavel Dvorkin
Re: Лучший синтаксис для перебора значений
От: Pavel Dvorkin Россия  
Дата: 06.04.06 05:25
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.


Да.. Есть еще проблемы на свете...

А проще всего было в Фортране

DO 100 I = 1,10

или с шагом

DO 100 I = 1,11,2


Только вот никому не советовали по ошибке вместо запятой ставить точку. Из-за этой точки в 60-е годы одна американская ракета при взлете самоуничтожилась (по крайней мере так говорят)
With best regards
Pavel Dvorkin
Re: Лучший синтаксис для перебора значений
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.04.06 05:40
Оценка: 46 (5) :)
Здравствуйте, VladD2, Вы писали:
VD>В общем, приветствуются любые мысли.
Мысль такая:
public class Range : IEnumerable<int>
{
    private int _low;
    private int _high;
    public IEnumerator<int> GetEnumerator()
    {
        for (int i = _low; i <= _high; i++)
            yield return i;
    }

    #region Construction
    public Range(int low, int high)
    {
        _low = low;
        _high = high;
    }
    public static Range Indexes<T>(T[] array)
    {
        return new Range(0, array.Length - 1);
    }

    #endregion

    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    #endregion
}

использование:
int[] a = new int[5];
foreach(int i in Range.Indexes(a)) // нет выбора между Length/Length-1
  Console.Write(i);

foreach(int i in new Range(0, 10))
  Console.Write(i);

Предполагается набор перегруженных конструкторов для указания step. Предполагается наличие свойства Reverse для обращения обхода. Предполагается наличие операций пересечения/объединения интервалов. Велком
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Лучший синтаксис для перебора значений
От: Pavel Dvorkin Россия  
Дата: 06.04.06 05:48
Оценка: +1 -1
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, VladD2, Вы писали:

VD>>В общем, приветствуются любые мысли.
S>Мысль такая:

<skipped>

М-да... Похоже, пора объявить конкурс на самую длинную реализацию цикла for...

Господа, а не кажется ли Вам, что для того, чтобы сравнивать нынешний программный продукт по числу LOC c тем, что писали 10 лет назад, надо для нынешнего продукта автоматически применять понижающий коэффициент, равный так примерно 10 ?

P.S. А вообще дискуссия начинает понемногу напоминать незавбвенную "Hello, World".
With best regards
Pavel Dvorkin
Re: Лучший синтаксис для перебора значений
От: vdimas Россия  
Дата: 06.04.06 05:57
Оценка:
Здравствуйте, VladD2, Вы писали:

Если использовать foreach, то надо подразумевать, что x итерирует по множеству, соответственно запись множества при использовании оператора цикла и при самостоятельном использовании должна быть одинакова, Ruby — как раз тому пример.

Если же мы просто определяем границы и правила итерации (шаг и выход за границы), то ИМХО, оператор for предпочтительней.

Это по самому ключевому слову было.

Далее.

Для первого случая, ИМХО, надо придумать операторы порождения потока, результат применения которых неплохо смотрелся бы как IEnumerator<> или IEnumerable<>.

Почему бы не взять "знакомые" конструкции с других языков (ruby, pascal)?

[1 .. 3]        // от 1-го до 3-х включительно
[1 .. 10; 2] // шаг 2

[0 .. 10, 20 .. 30; 5] = {0, 5, 10, 20, 25, 30}

public delegate T NextIndexGenerator<T>(T current); // позволить использовать формулу для вычисления следующего члена ряда 
                                                    // исходя из значения предыдущего

[1 .. 1024; @current*2] = {1, 2, 4, 8, ..., 1024}

[0.1 .. 0.9, Math.Sqrt] = {0.1, 0.316, ..., 0.8999 } // ряд, сходящщийся к 1.0 по формуле next = sqrt(current);



Несчет неудобства array.Length-1 ничего сказать не могу, лично мне безразлично. Если кому-то важно, то можно оппробовать разные формы записи для открытых и закрытых диапазонов. Я бы предложил так:
[0..array.Length),

но боюсь, случайная опечатка в парных скобочках будет пересекаться с семантикой, что не есть гут. Может быть будут еще идеи как указать открытый диапазон? А может быть ввести некое ключевое слово, типа before:
[1 .. before 1024; @current*4]


----------
Насчет же указания границ перебора для цикла for — все предложенные варианты интересны (хоть и записаны были как foreach). Действительно, надо взять несколько наиболее встречающихся случаев переборав цикла и заточить синтаксис под них.

Вот еще варианты:
for(i from 0 to 10 step 2) // закрытый диапазон слева и справа

for(i from 0 before 10 step 5) // открытый диапазон

Кстати, почему бы не сделать from 0 по умолчанию для before (самый востребованный сценарий использования)?

Совсем коротко выходит:
int[] arr = new int[10];

for(i before arr.Length) 
    arr[i]=i*i;
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Лучший синтаксис для перебора значений
От: Кодёнок  
Дата: 06.04.06 06:00
Оценка: 27 (1) +1
Здравствуйте, VladD2, Вы писали:

VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.


VD>foreach (i in 0..3) // выдает последовательность 0, 1, 2, 3

VD>этот синтаксис хорош, но неудобен когда нужно перебрать значения индекса некой коллекции:
VD>foreach (i in 0..array.Length — 1) // не нравится этот "- 1"

Есть такие мысли:

1. Использовать генератор xrange() (или range()) для открытых справа диапазонов. При этом ".." будет соответствовать закрытому интервалу, вроде closed_range()

2. for (int i = 0 while i < 10), for (int i = 0 while i <= 10 step 2). Но мне очень не нравится, что < можно спутать с <=, по сути это тот же Си-шный for.

3. Для перебора индексов использовать какой-нибудь генератор вроде IndexesOf из твоего примера и этим ограничиться.

4. Финт: for (int i = 0 to 10) для открытого сверху (0..9), for (int i = 1 upto 10) для закрытого (1..10). Перепутать трудно, визуально длина слов разная. Но с первого взгляда кажется непривычным. Собственно, сами слова "to" и "upto" можно исопльзовать вместо двух и трех точек для конструирования интервалов, не только в конструкции for.
Re[3]: Лучший синтаксис для перебора значений
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 06.04.06 06:01
Оценка: 23 (1) +2 -1 :)
Pavel Dvorkin,

PD>Господа, а не кажется ли Вам, что для того, чтобы сравнивать нынешний программный продукт по числу LOC c тем, что писали 10 лет назад, надо для нынешнего продукта автоматически применять понижающий коэффициент, равный так примерно 10 ?


Чаще всего величина библиотечного кода нас не волнует. Можно хоть на 1024 умножить, главное чтобы потом в своём файле иметь возможность писать
(+/ % #) list


вместо
int n = list.size();
double sum = 0;
for (int i = 0; i < n; i++)
    sum += list[i];
return sum/n;
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[4]: Лучший синтаксис для перебора значений
От: Кодёнок  
Дата: 06.04.06 06:08
Оценка: +1
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Чаще всего величина библиотечного кода нас не волнует. Можно хоть на 1024 умножить, главное чтобы потом в своём файле иметь возможность писать

LCR>(+/ % #) list

LCR>вместо

LCR>int n = list.size();
LCR>double sum = 0;
LCR>for (int i = 0; i < n; i++)
LCR> sum += list[i];
LCR>return sum/n;

Отличная иллюстрация двух диких крайностей

Я предпочитаю золотую середину:

sum = reduce(float.__add__, list, 0.0)


В других языках reduce имеет имя fold или accumulate.
Re[5]: Лучший синтаксис для перебора значений
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 06.04.06 06:25
Оценка: +1 :)
Кодёнок,

Кё>Отличная иллюстрация двух диких крайностей


Кё>Я предпочитаю золотую середину:

Кё>
Кё>sum = reduce(float.__add__, list, 0.0)
Кё>

Я так полагаю, это Питончик? Да, там кстати считалось среднее
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[6]: Лучший синтаксис для перебора значений
От: Кодёнок  
Дата: 06.04.06 06:43
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

Кё>>Я предпочитаю золотую середину:

Кё>>sum = reduce(float.__add__, list, 0.0)
LCR>Я так полагаю, это Питончик? Да, там кстати считалось среднее

Совершенно верно, питон Но можно и другие языки:
return Nemerle.Collections.List.FoldLeft(lisT, 0, fun(a,b) {a+b}) / x.Length


Ну а насчет среднего — не намного сложнее, return reduce(float.__add__, lisT, 0.0)/len(lisT)

Кстати, а как в Nemerle сослаться на оператор + для класса, например, для целых? Пробовал System.Int32.op_Add и System.Int32.operator+, в документации не знаю где искать.
Re[5]: Лучший синтаксис для перебора значений
От: Kemsky  
Дата: 06.04.06 06:54
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>do while применяется так редко не поэтому, а потому что ситуации, когда необходимо выполнить тело цикла один раз обязательно, встречаются намного реже, чем ситуации, когда это не требуется.


Это зависит от того, как мыслит человек. Например, у меня большая часть циклов вообще полуторные: одна часть цикла должна выполняться на одну итерацию больше, чем другая. А чистые do и while, как вырожденные случаи, встречаются реже.
Re[3]: Лучший синтаксис для перебора значений
От: Kemsky  
Дата: 06.04.06 07:21
Оценка: -3 :))
Здравствуйте, VladD2, Вы писали:


VD>Понимаш ли в чем дело? С-шный for никто не отменяет. Но его гибкость выливается в ошибки и усложнение чтения кода когда он используется для простых вещей.


VD>Ведь если так мыслить, то даже самая приметивная программа станет архи-сложной.


VD>По этому за конструкцией "for (int i = 0; i < array.Length; i++)" ты улавливашь некий паттерн. В данном случае "перебрать все индексы массива array". Но этот паттерн тебе приходится угадывать. А тут есть две проблемы. 1. Ты можешь не врено принять за этот паттерн просто похожую конструкцию, например, "for (int i = 0; i <= array.Length; i++)" или "for (int i = 0; i < array.Length; i--)". 2. Разглядывать паттерны в накромождениях кода очень не просто.


VD>Посему код написанный в таком стиле плохо читается.


Эта сложность служит барьером от случайных людей. Можно избавить программистов от проблем на этом, весьма низком уровне. Однако, если человек не может научиться преодолевать подобные препядствия, то польза от него, как программиста, довольно сомнительна. Оперирование паттернами более высокого уровня, в действительности, намного сложнее. Если, конечно, речь не идёт о "Copy" и "Paste" фрагментов кода из документации и др. источников.
Re[2]: Лучший синтаксис для перебора значений
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.04.06 07:35
Оценка: +1
Здравствуйте, vdimas, Вы писали:
V>Несчет неудобства array.Length-1 ничего сказать не могу, лично мне безразлично. Если кому-то важно, то можно оппробовать разные формы записи для открытых и закрытых диапазонов. Я бы предложил так:
V>
[0..array.Length),

Поскольку итерация в массиве — очень частая штука, имеет смысл сделать ее отдельной операцией. В дотнете уже придумано отличное решение — в большинстве случаев мне совсем не надо париться с индексом благодаря встроенному foreach:
int[] a = new int[] {1, 2, 3, 4};
int sum = 0;
foreach(int item in a)
  sum += item;

В тех редких случаях, когда мне все же нужен именно индекс, я бы предпочел вообще отказаться от манипуляций с Length. Оптимально было бы так:
int[] a = new int[] {1, 2, 3, 4};
int weightedSum = 0;
foreach(int i in a.Indexes)
  weightedSum += i*a[i];

V>но боюсь, случайная опечатка в парных скобочках будет пересекаться с семантикой, что не есть гут. Может быть будут еще идеи как указать открытый диапазон? А может быть ввести некое ключевое слово, типа before:
Мне кажется, сама проблема использования диапазонов в значительной мере надумана. Во-первых, диапазон настолько часто приделан к коллекции, что проще сделать нарошные операции извлечения диапазона напрямую, чем давать человеку возможность ошибиться при "двухстадийной" схеме — сначала вытаскиваем границы, а потом формируем из них диапазон.
Во-вторых, все эти скобочки экономят буквально одиночные символы, в ущерб понятности и безошибочности. По мне, так гораздо лучше ввести необходимые функции-конструкторы диапазонов:
Range(low, high) // для (1, 4) переберет 1, 2, 3, 4
ExclusiveRange(beforeLow, afterHigh) // для (1, 4) переберет (2, 3)
Since(low) // для (1) будет перебирать 1, 2, 3, ... до бесконечности
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Лучший синтаксис для перебора значений
От: ie Россия http://ziez.blogspot.com/
Дата: 06.04.06 07:53
Оценка: 24 (1)
Здравствуйте, VladD2, Вы писали:

VD>Хочется услышать мнение народа о том как бы он хотел видеть паттерн перебора значений из некоторого диапазона.


foreach (i in (0, 4, 7)) // выдает последовательность 0, 4, 7
foreach (i in (0, 4..7+)) // выдает последовательность 0, 4, 5, 6, 7
foreach (i in (0, 4..7-, 12..14+)) // выдает последовательность 0, 4, 5, 6, 12, 13, 14


Но так Nemerle сделать не даст
Я в недавно в образовательных целях сделал такой макрос:
    macro @foreachIn (inexpr, body)
    syntax ("foreachIn", "(", inexpr, ")", body)
    {
        def intervalExecute(pat, intervalExpr, body)
        {
            match (intervalExpr)
            {
                | <[ $first .. $last ]> => 
                    <[
                        mutable i = $first;
                        def last = $last;
                        while (i <= last) 
                        {
                            def $pat = i;
                            $body;
                            i++;
                        }
                    ]>
                | <[ $single ]> => 
                    <[
                        def $pat = $single;
                        $body;
                    ]>
                | _ => throw Exception("foreachIn Usage: foreachIn(i[2..5, 7..10])");
            }
        }

        match (inexpr) 
        {
            | <[ $pat $[$single] ]>
            | <[ $pat [$single] ]> =>
                intervalExecute(pat, single, body)
            | <[ $pat $[..$list] ]>
            | <[ $pat [..$list] ]> =>
                {
                    def m(intervalExpr) { intervalExecute(pat, intervalExpr, body) }
                    mutable s = [];
                    foreach (i in list)
                        s =  m(i) :: s;
                    <[ { .. $(s.Reverse()) } ]>;
                }
            | _ => throw Exception("foreachIn Usage: foreachIn(i[2..5, 7..10])");
        }
    }

Использовать так:
    def p = 6;
    def q = 9;
    foreachIn (i[2..4, p..q, 11, 13..15])
        printf("%d\n", i);

Но так как это делалось исключительно в образовательных целях, о синтаксисе паттерна перебора сильно не задумывался.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Re: Лучший синтаксис для перебора значений
От: igna Россия  
Дата: 06.04.06 07:53
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>foreach (i in 0...3) // то есть добавляется третья точка.

VD>Но это не интуитивно и легко путается с вариантом с двумя точками.


А если так?:

foreach (i in 0..<3)
Re: Лучший синтаксис для перебора значений
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 06.04.06 08:00
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>этот синтаксис хорош, но неудобен когда нужно перебрать значения индекса некой коллекции:

VD>
VD>foreach (i in 0..array.Length - 1) // не нравится этот "- 1"
VD>


Для полноты картины:
  for I := Low(A) to High(A) do;


Я для своих классов в которых нумерация начинается с нуля, ввожу еще одно поле Limit = Length — 1. В этом случае цикл:

  for I := 0 to A.Limit do;


Хорошая реализация в MATLAB. Там цикл имеет вид
  for i = A
    ...
  end


где i это переменная, а A это массив (рассматривается как одномерный). Поскольку массивы можно определить при помощи оператора ":", то Цикл от 1 до 10 может быть записан как

  for i = 1:10
    ...
  end


Цикл от 10 до 1 дожет быть записан как
  for i = 1:10:-1
    ...
  end


Распечатать все элементы массива можно просто
  for i = A
    print(i)
  end


Если при этом добавить для классов свойство Range, то получим
  for i = A.Range
    A(i) = 0.0
  end
Re: Лучший синтаксис для перебора значений
От: Undying Россия  
Дата: 06.04.06 08:00
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Мне в голову прили следующие варианты:

VD>
VD>foreach (x where 0 >= x < 10 step 1) // "step 1" необязательный параметр позволяющий задать шаг отличный от еденицы
VD>


И чем это лучше кода for (x = 0; x < 10; ++x)?

Почему так широко используется foreach? Потому что полностью соответствует задаче — "последовательно получить элементы коллекции". For задаче не соответствует, т.к. задача требует получения элементов, а не индексов и не содержит ни условия для отбора индексов, ни шага изменения индекса.

Ты же рассматриваешь другую задачу, а именно — "получить индексы в диапазоне от 0 до 10 с шагом 1". В чем здесь заключается несоответсвие for'а задаче? For работает именно с индексами, в нем задается диапазон и шаг, задавать еще что-то не надо. For для такой задачи по меньшей мере не хуже любой другой формы записи, соответственно не понятно стремление к его замене и тем более замене дублирующей.
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Re[7]: Лучший синтаксис для перебора значений
От: ie Россия http://ziez.blogspot.com/
Дата: 06.04.06 08:10
Оценка: 10 (1)
Здравствуйте, Кодёнок, Вы писали:

Кё>Кстати, а как в Nemerle сослаться на оператор + для класса, например, для целых? Пробовал System.Int32.op_Add и System.Int32.operator+, в документации не знаю где искать.


Должно быть Int32.op_Addition. По крайней мере компилиться, но во время выполнения падает, видимо баг (может уже поправили).
... << RSDN@Home 1.1.4 beta 7 rev. 447>>
Превратим окружающую нас среду в воскресенье.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.