LINUX.ORG.RU

Ruby for..end..if..else

 


1

2

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

#!/usr/bin/ruby
#coding: utf-8
arr = [1,2,3,4,5]
key = true
arr.each do |a|
	if a == 4 
		puts a
		key = false
		break
	end
end
if key
	puts 'цикл завершился, нет соответствий'
else
	puts 'цикл прервался, найдено соответствие условию'
end
Всегда казалось что это выглядит криво но особо не парило. Сейчас решил разобраться в этом вопросе и обнаружил что циклы в ruby после выполнения возвращают переданные им параметры
test = for i in 1..5; end
puts test.inspect
> 1..5
test = arr.each { |a| }
puts test.inspect
> [1, 2, 3, 4, 5]
В случае если цикл прерывается по break он возвращат nil. Таким образом можно написать например вот такой код
#!/usr/bin/ruby
#coding: utf-8

arr = [1,2,3,4,5]

key = arr.each do |a|
	if a == 4
		puts a
		break
	end
end ? true : false

if key
	puts 'цикл завершился'
else
	puts 'цикл прервался, найдено соответствие условию'
end
Как вам такое?)

UPD: точнее наверно сказать, что это фича не циклов, а итераторов

★★★★★

for a in arr:
    if a == 4:
        print(a)
        print("Цикл завершился, есть соответствия")
        break
else:
    print("Цикл завершился, нет соответствий")
PolarFox ★★★★★ ()
Последнее исправление: PolarFox (всего исправлений: 1 )

это не цикл, это отображение (map).

exception13 ★★★★★ ()
$cat array.rb 
arr = [1,2,3,4,5]
puts arr.include?(4)
$ruby array.rb
true

Руби не знаю, глянул в документацию по массивам, потсатил 15 секунд. Итого

Хреново быть тобой (

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

в качестве элементов множества могут быть сложные типы данных.

exception13 ★★★★★ ()

Хреновый ты выбрал пример.
Щас же набегут вундеркинды, которые научат тебя родным методам.

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

Руби не знаю, глянул в документацию по массивам,

А если это массив хешей и нужно найти соответствие по определенному ключу?

потсатил 15 секунд. Итого Хреново быть тобой (

В следующий раз потрать больше 15 секунд.

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

ну это пока ему не надо. а потом приспичит посчитать кол-во совпадений или еще что (у него же не хэш а массив).

exception13 ★★★★★ ()

Только что опытным путём выяснил что break работает как return, в пределах блока. Вот уж неизведанная земля.

key = arr.each do |a|
  if a == 4 
    puts a
    break(:yes!)
  end
end
vladimir-vg ★★ ()
arr = [1,2,3,4,5]

class Matcher
  def initialize(array, target)
    @array = array
    @target = target
  end

  def do
    if @array.include?(@target)
      puts @target
      puts "ASD"
    else
      puts "FGS"
    end
  end
end

Matcher.new(arr, 4).do

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

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

неизведанная земля

документацию читать надо, епт

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

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

Лучше расскажи зачем для подобной задачи придумывать новый класс?

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

Точно так же как и each+break, только красивее и меньше кота писать. Олсо, всяко, декомпозиция должна быть, так что в любом случае ничего не должно быть толстым.
А вот break очень царапает. Ты такой, пустился в свободные итерации и на-ёпт!. Хотя это всё микодрочерство.

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

кто то сказал анонимная функция? не, я точно слышал что кто то сказал анонимная функция.

exception13 ★★★★★ ()

Всегда казалось что это выглядит криво

Зато это легко читать и понимать. Длинные цепочки select'ов/map'ов в связке с "? :" дает на выходе какой-то нечитаемый адок.

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

Лучше расскажи зачем для подобной задачи придумывать новый класс?

Проблема в том, что на самом деле нет никакой задачи.

pechorin ()

Как вам такое?)

Вырвиглазненько.

Советую внимательнее ознакомиться с Enumerable и настроить отступы:

if [1,2,3,4,5].any? { |a| (puts a; true) if a == 4 }
  puts 'цирк прервался, найдено соответствие условию'
else
  puts 'цирк завершился'
end

И да, пример надуманный, из процедурного программирования. В каком gem'е вы такое встречали?

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

В раби циклы - это циклы. А вот то, что ТС по своему скудоумию называет циклами, как раз методы, принимающие анонимные функции в качестве аргумента.

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

В раби циклы - это циклы. А вот то, что ТС по своему скудоумию называет циклами, как раз методы, принимающие анонимные функции в качестве аргумента.

ТС написал для особо одаренных

UPD: точнее наверно сказать, что это фича не циклов, а итераторов

TDrive ★★★★★ ()

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

Обычно это решалось так:

if arr.any? {|v| какое-нибудь условие}
  что-нибудь выполнить
else
  сделать что-нибудь другое
fi

Кстати, настоящие циклы, а не методы, в раби выглядят так:

while условие
  тело
end

until условие
  тело
end

тело while условие

тело until условие

for i in значения
  тело
end

Как известно, до 90% программистов не владеют языком, на котором «программируют». А в раби, похапэ и питоне эта величина достигает 99%.

А еще ТСу русский язык бы подучить не мешало. «сделать, что нибудь другое» - это вещь посильнее даже быдлокода на руби.

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

Фейлишся.

Нет, это просто ты с матчастью не знаком.

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

Потому что эту задачу нужно выполнять «очень часто». Ты предлагаешь open code'ить каждый раз?

anonymous ()

А я всё думал, для кого они в питоне else для for присобачили... оказалось, для тебя. Чтобы закручивать бигуди костылями.

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

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

Гы. Пытался писать в стиле быдла, но не осилил: один раз написал с ошибкой, а в следующем абзаце - нет. :D

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

Как будто что-то плохое. И да, чини парсер сарказма, он у тебяч поломан.

comp00 ★★★★ ()

Как вам такое?)

Руби рубит, именно за это мы его (или её?) рубим^Wлюбим.

Стоит только добавить, что если подобное приходится реализовывать действительно очень часто, то надо выносить этот функционал в отдельный метод, благо в руби доопределить класс/модуль ни разу не проблема.

Apple-ch ★★ ()
Ответ на: комментарий от Deleted

А как такое сделать в C++ или на Java?

Как обычно, через жопу.

#include <functional>
#include <iostream>
#include <vector>

template <typename InputIterator, typename Test>
bool any(InputIterator first, InputIterator last, Test test)
{
    while (first != last)
    {
        if (test(*first))
            return true;
        ++first;
    }
    return false;
}

using namespace std;

int main(void)
{
    vector<int> v = {3, 5, 7, 8, 1};
    if (any(v.begin(), v.end(), [](int i){return i % 2 == 0;}))
    {
        // do something
    }
    else
    {
        // do something else
    }
    return 0;
}
anonymous ()
Ответ на: комментарий от feofil

А я всё думал, для кого они в питоне else для for присобачили...

То есть зачем присобачили else для while и try-except для тебя ясно?) Ветка else срабатывает, если в цикле не сработала инструкция break, и он отработал все итерации. Юзкейсы сложно придумать, но кому-нибудь пригодится.

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