LINUX.ORG.RU

Работа с последовательностями в разных языках

 , , , ,


7

9

Навеяно темой Ментальный вирус, пример взят и дополнен оттуда. Интересует реализация подобной операции на других языках. Лично я хотел бы увидеть на Lisp, Java, Smalltalk, Erlang.

array = ["John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather"]

puts array.select{|v|v[/^J[a-z]+/]}. # ВЫБРАТЬ ПО someregexp
each_slice(3). # КАЖДЫЙ КУСОК ПО 3 ЭЛЕМЕНТА
map{|v| "#{v[0]} and #{v[1]} follow #{v[2]}"}. # ПОДСТАВИТЬ ЗНАЧЕНИЯ В СТРОКУ
join("\n") # ОБЪЕДИНИТЬ
# John and James follow Jakob
# Janette and Jean follow Juilia

Пошагово для тех, кто не знаком с Ruby:

array.select{|v|v[/^J[a-z]+/]}
# ["John", "James", "Jakob", "Janette", "Jean", "Juilia"]
array.select{|v|v[/^J[a-z]+/]}.
each_slice(3).to_a # в массив
# [["John", "James", "Jakob"], ["Janette", "Jean", "Juilia"]]
array.select{|v|v[/^J[a-z]+/]}.each_slice(3).
map{|v| "#{v[0]} and #{v[1]} follow #{v[2]}"}
# ["John and James follow Jakob", "Janette and Jean follow Juilia"]
array.select{|v|v[/^J[a-z]+/]}.each_slice(3).map{|v| "#{v[0]} and #{v[1]} follow #{v[2]}"}.
join("\n") 
# "John and James follow Jakob\nJanette and Jean follow Juilia"

Использовать только стандартную библиотеку.

Целесообразность операции не важна. Вопрос кратности количества найденных элементов трем не рассматриваем.



Последнее исправление: ymn (всего исправлений: 3)

И снова руби!

class Array
  def j_to_n reg, part
    self.select{|v|v =~ reg}.each_slice(part).map{|v| yield *v }.join("\n")
  end
end

arr=["John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather"]

arr.j_to_n( /^J[a-z]+/, 3 ){|a,b,c| "#{a} and #{b} follow #{c}" }

special-k ★★★
()

Вопрос кратности количества найденных элементов трем не рассматриваем.

кстати в моем варианте «хвост» из одного или двух человек запишется корректно и читабельно ^_^

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

кстати в моем варианте «хвост» из одного или двух человек запишется корректно и читабельно ^_^

В моем хаскелл варианте хвост простос ингнорируется. Вопрос, что тут является корректным и читабальным?

Waterlaz ★★★★★
()

Perl

Код на perl5. Всего один пробел вне строковых констант.

@_=grep/^J/,qw(John James Jakob Peter Janette Tom Vasya Jean Juilia Heather);
say map{sprintf"%s and %s follow %s\n",splice@_,0,3}(1..@_/3)

anonymous
()
var list=List("John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather")

list.filter(x=>x.matches("""J[a-z]+""")).sliding(3,3).map(x=>x(0)+" and "+x(1)+" follow "+x(2)).foldLeft("")((a,b)=>a+b+'\n')

я так понимаю на java всем лень такое писать. //и да, string interpolation надо бы. Пойду обновлюсь

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

вот вам

    public static String java_style(String...array){
        StringBuilder sb = new StringBuilder();
        List<String> s = new ArrayList<String>(3);
        for (String string : array) {
            if(string.startsWith("J")){
                s.add(string);
            }
            if(s.size()==3){
                sb.append(s.get(0)).append(" and ").append(s.get(1)).append(" follow ").append(s.get(2)).append('\n');
                s.clear();
            }
        }
        sb.deleteCharAt(sb.length()-1);
        return sb.toString();
    }

maloi ★★★★★
()
Ответ на: комментарий от special-k

Давай нам нашумевший io)

Пришлось в List собственный метод добавить:

Regex

List do (
    split_by_count := method(step,
        result := list() ; acc := list()
        self foreach(v,
            acc append(v)
            if (acc size == step,
                result append(acc)
                acc = list()
            )
        )
        if (acc size > 0,
            result append(acc)
        )
        result
    )
)

l := list("John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather")
l select(matchesRegex("^J[a-z]+")) split_by_count(3) map(v, v at(0) .. " and " .. v at(1) .. " follows " .. v at(2)) join("\n") print

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

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

надо очевидно либо обрезать хвост, либо вывести его нормально, а не «Jean and follow», оба варианта корректны

wota ★★
()
Ответ на: Perl от anonymous

Всего один пробел вне строковых констант.

Ну.. у всех свои приоритеты (подчас не слишком очевидные конечно)..

special-k ★★★
()

Синтаксисом померились теперь о быстродействии

У меня 10^6 итераций :
sbcl - 4.5sec
python - 6.4sec
ruby - 12.6sec
tcl - 18sec

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

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

maloi ★★★★★
()
Ответ на: комментарий от special-k

Там нет блоков. :) Любой код - это данные. Метод получает свои аргументы как синтаксические деревья и дальше может с ними делать что угодно. Например, вычислить в контексте вызвавшего метода (чтоб будет эквивалентно вызову блока).

geekless ★★
()
Ответ на: комментарий от dr_jumba
a = {"John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather"}

reshape(a(char(a)(:,1)=='J'),2,3)

а вот с выводом че-то туплю. сейчас arrayfun присобачу и должно заработать...

dikiy ★★☆☆☆
()

Про самый главный-то язык почему забыли?

l='John James Jakob Peter Janette Tom Vasya Jean Juilia Heather'
result="$(echo "$l" | sed 's, ,\n,g' | egrep '^J[^ ]*' | while read a; read b ; read c ; do echo "$a and $b follow $c" ; done)"

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

Синтаксисом померились теперь о быстродействии

~$ cat 1.cpp
inline void add( char*& d, const char* s ) {
    while(*s) *d++=*s++;
}

int main() {
    const char* v[] = {"John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather"};
    char buf[128];

    for(int k=0;k<1000000;++k) {
        int n=0; char* s=buf;
        for( auto i : v ) if(*i=='J') {
            if(n++) {
                if(n%3==2) add(s," and ");
                else if(n%3) *s++='\n';
                else add(s," follow ");
            }
            add(s,i);
        } 
        *s=0;
    }
}
~$ g++ -Ofast -std=c++11 1.cpp
~$ time ./a.out 

real	0m0.048s
user	0m0.048s
sys	0m0.000s
wota ★★
()
Последнее исправление: wota (всего исправлений: 1)
Ответ на: комментарий от RedPossum

это не так уж сложно поправить

    public static String java_style(String...array){
        StringBuilder sb = new StringBuilder();
        List<String> s = new ArrayList<String>(3);
        for (String string : array) {
            if(string.matches("^J[a-z]+")){
                s.add(string);
            }
            if(s.size()==3){
                sb = sb.length()>0?sb.append('\n'):sb;
                sb.append(s.get(0)).append(" and ").append(s.get(1)).append(" follow ").append(s.get(2));
                s.clear();
            }
        }
        return sb.toString();
    }

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

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

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

Ваш java_style говно, вы ничего не понимаете в java_style.

Вот кошерная вариация на тему:

Object [] strs = new ArrayList<String>(){{
	for(String str : asList("John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather")){
		if(str.startsWith("J")) add(str);
	}
}}.toArray();

for(int i = 0; i <= (strs.length - 3); i+=3){
	System.out.format("%s and %s follows %s \n", copyOfRange(strs, 0+i, 3 + i));
}
DiKeert ★★
()
Ответ на: комментарий от invy

не выкинул, легко можно проверить увеличив кол-во итераций

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

Если забить на то, что эта штука падает после выполнения задачи, то можно сделать вот так:

for(int i = 0; true; i+=3){
	System.out.format("%s and %s follows %s \n",
			copyOfRange(new ArrayList<String>(){{
				for(String str : asList("John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather"))
					if(str.startsWith("J")) add(str);
			}}.toArray(), 0+i, 3 + i));
}
DiKeert ★★
()
Ответ на: комментарий от RedPossum
val l = List("John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather")
println(l.filter(_.matches("J[a-z]+")).sliding(3, 3).map(x=>s"${x(0)} and ${x(1)} follow ${x(2)}").mkString("\n"))
kamre ★★★
()

Скалу уже писали.

Java, петросян-mode

import static com.google.common.collect.Collections2.*;
import static com.google.common.collect.Iterables.*;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;

public class MainClass {
    public static void main(String[] arv){
        List<String> array = ImmutableList.of(
                "John", "James", "Jakob", "Peter", "Janette",
                "Tom", "Vasya", "Jean", "Juilia", "Heather");

        Collection<String> filtered = filter(array, new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return s.startsWith("J");
            }
        });

        Iterable<List<String>> partitioned = partition(filtered, 3);

        Iterable<String> formatted = transform(partitioned, new Function<List<String>, String>() {
            @Override
            public String apply(List<String> s) {
                return MessageFormat.format("{0} and {1} follow {2}", s.get(0),s.get(1),s.get(2));
            }
        });

        String result = Joiner.on("\n").join(formatted);
        System.out.println(result);
    }
}

Или без рюшечек

import static com.google.common.collect.Collections2.*;
import static com.google.common.collect.Iterables.*;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;

import java.text.MessageFormat;
import java.util.List;

public class MainClass {
    public static void main(String[] arv){
        List<String> array = ImmutableList.of(
                "John", "James", "Jakob", "Peter", "Janette",
                "Tom", "Vasya", "Jean", "Juilia", "Heather");

        String result = Joiner.on("\n").join(transform(partition(filter(array, new Predicate<String>() {
            @Override
            public boolean apply(String s) {
                return s.startsWith("J");
            }
        }), 3), new Function<List<String>, String>() {
            @Override
            public String apply(List<String> s) {
                return MessageFormat.format("{0} and {1} follow {2}", s.get(0),s.get(1),s.get(2));
            }
        }));
        
        System.out.println(result);
    }
}
vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от RedPossum

торжественно обещаю себе выучить наконец все collections api

все

Придется тебя разочаровать. Но mkString да, боян

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

Придется тебя разочаровать. Но mkString да, боян

ну хотя бы большую часть, потому как даже forall не пользую, одни fold'ы да map'ы

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

Если и писать такие ленты, то каждую операцию с новой строчки, начиная с точки с одинаковым отступом

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

Там есть и помощнее штуки, которые заменять фолдами не очень приятно, напиример collect, partition, takeWhile, dropWhile, split

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

Just for lulz, согласно даже Guava guidelines не надо злоупотреблять ФП до Java 8, иначе будет гуавно

vertexua ★★★★★
()
Ответ на: комментарий от anonymous
~$ cat 1.cpp
#include <cstring>
#include <stdint.h>

inline void add( char*& d, const char* s ) {
    do *d++=*s++; while( *s );
}

int main() {
    const char* v[] = {"John", "James", "Jakob", "Peter", "Janette", "Tom", "Vasya", "Jean", "Juilia", "Heather"};
    char buf[128];

    int64_t sand; memcpy( &sand, " and ", 5 );
    int64_t sfollow; memcpy( &sfollow, " follow ", 8 );

    for(int k=0;k<1000000;++k) {
        int n=0; char* s=buf;
        for( auto i : v ) if(*i=='J') {
            if(n++) {
                if(n%3==2) { *((int64_t*)s)=sand; s+=5; }
                else if(n%3) *s++='\n';
                else { *((int64_t*)s)=sfollow; s+=8; }
            }
            add(s,i);
        } 
        *s=0;
    }
}
~$ g++ -Ofast -std=c++11 1.cpp
~$ time ./a.out 

real    0m0.028s
user    0m0.024s
sys    0m0.000s

для полного батхерта

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

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

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