четверг, 28 февраля 2008 г.

Разединяем строки...обьединяем строки.

Итак...задачка. Есть массив строк. Каждую строку в массиве нужно разделить по указанному разделителю, потом все полученные строки обьединить по еще одному указанному разделителю.

Если не очень понятно - нужно из таких строк: "word1-word2", "word3-word4", "word5-word6"
получить вот такую строку:
word1:word2:word3:word4:word5:word6

C#:

Увы, стандартная функция Join не работает с IEnumerable. Поэтому пришлось написать свою. Также нет стандартной функции reduce. Поэтому пришлось написать свою. Это не так уж и важно, поскольку к выводам не относится. Итак, код:

Способ1:

string[] a = { "word1-word2", "word3-word4", "word5-word6" };

Console.WriteLine(":".join(a.SelectMany(x=>x.Split('-'))));


Способ 2:

string[] a = { "word1-word2", "word3-word4", "word5-word6" };

Console.WriteLine(a.SelectMany(x => x.Split('-')).reduce((x, y) => x + ":" + y));



Python. Тут ничего дописывать не пришлось.

Способ 1:

a = ["word1-word2", "word3-word4", "word5-word6"]

print ":".join([x for word in a for x in word.split('-')])


Способ 2:

a = ["word1-word2", "word3-word4", "word5-word6"]

print reduce(lambda x,y:x+":"+y,[x for word in a for x in word.split('-')])



К чему это я...
С++, решение "в лоб"

    vector<string> w;

    w.push_back("word1-word2");

    w.push_back("word3-word4");

    w.push_back("word5-word6");

 

    string result;

 

    for(vector<string>::const_iterator v = w.begin();v!=w.end();++v)

    {

        const vector<string>& w1 = split_string(*v,"-");

        for(vector<string>::const_iterator v1 = w1.begin();v1!=w1.end();++v1)

        {

            if(!result.empty())

                result+=":";

            result+=*v1;

        }

    }

    cout << result << endl;


Попробуем функционально? "Без проблем":

    vector<string> w;

    w.push_back("word1-word2");

    w.push_back("word3-word4");

    w.push_back("word5-word6");

 

    cout << join_string(select_many(w,bind(split_string,_1,("-"))),":") << endl;

Почему "без проблем" в кавычках...?
Потому что сначала я попытался достигнуть результата используя только std::for_each и bind. Не получилось. Пришлось написать (ну помимо join_string и split_string функцию select_many.

template<class _Container,class _Fn1> inline

_Container select_many(const _Container& container, _Fn1& _Func)

{   

    _Container res;

    for(_Container::const_iterator v = container.begin();v!=container.end();++v)

    {

        _Container tmp = _Func(*v);

        for(_Container::const_iterator v1 = tmp.begin();v1!=tmp.end();++v1)

            res.push_back(*v1);

    }

    return res;

}



В принципе по своей сути она похожа на аналогичные в C# и Python, но увы - фактически до них ей ну очень далеко. Разница огромна, даже расписывать не буду.

К чему это я...

Если бы у меня была возможность выбрать какую возможность добавить в следующую версию С++ я бы пожалуй выбрал питоновские генераторы (они же шарповые IEnumerable).

Комментариев нет: