2014-02-16 2 views
4

У меня есть список, содержащий многоуровневые вложенные списки. В каждом списке могут быть строки и экземпляры других типов.Как объединить все строки во вложенном списке?

E.g.

var list = [ 'a', 'w', ['e', ['f', new Object(), 'f'], 'g'], 't', 'e']; 

Я хочу написать функцию (скажет compress), чтобы объединить строки со своими братьями и сестрами, и оставить другие экземпляры типа нетронутыми, и, наконец, получить список, который не имеет вложенный список.

компресс (список) { // как? }

И результат compress(list) будет:

['awef', new Object(), 'fgte'] 

Это быстрый и прозрачный раствор для него?

ответ

4

Terse и функциональный FTW

List compress(Iterable iterable) => concat(flatten(iterable)); 

Iterable flatten(Iterable iterable) => 
    iterable.expand((e) => e is Iterable ? flatten(e) : [e]); 

List concat(Iterable iterable) => iterable.fold([], (list, e) => 
    list..add((e is String && list.isNotEmpty && list.last is String) 
     ? list.removeLast() + e : e)); 
+0

Что, что 'list..add' делать? Выполнение 'add', но возврат' list'? Все еще не хватает какого-то функционального оператора приложения, такого как Haskell, и XQuery знают их ... 'List compress => flatten. concat; 'было бы действительно мило. –

+0

Да. Это метод каскада. Выражение оценивает список, поэтому функция возвращает список, но позволяет добавлять вызываемые в одном выражении. Мне действительно нравится ваш ответ лучше, то есть он более ясен. Я просто играл, чтобы узнать, как я могу получить код. –

+0

Сладкий, я все время отвращался от этого «возвратного списка». Я определенно предпочитаю ваш «сгладить», хотя «concat» было немного трудно читать. –

1

Вот мое предположение:

compress(List l, [List p]) => l.fold(p != null ? p : [], (List t, e) { 
    if (e is String) { 
    if (t.isEmpty || t.last is! String) t.add(e); 
    else t.add(t.removeLast() + e); 
    } else if (e is List) compress(e, t); 
    else t.add(e); 
    return t; 
}); 
0

Моя попытка

List flatten(List l) { 
    List result = ['']; 
    int cur = 0; 

    var add = (f) { 
    if(f is String) { 
     result[cur] += f; 
    } else { 
     result.add(f); 
     result.add(''); 
     cur += 2; 
    } 
    }; 

    l.forEach((e) { 
    if(e is List) { 
     flatten(e).forEach((e) => add(e)); 
    } else { 
     add(e); 
    } 
    }); 
    return result; 
} 
2

Это состоит из двух проблем, очень стандартной (выравнивающих список), а затем присоединяющихся струны адекватно.

flatten(Iterable l) => l.fold([], (List list, element) { 
    if (element is Iterable) 
    list.addAll(flatten(element)); 
    else 
    list.add(element); 
    return list; 
}); 

concat(Iterable l) => l.fold([], (List list, element) { 
    if (element is String && !list.isEmpty && list.last is String) 
    list.add(list.removeLast() + element); 
    else 
    list.add(element); 
    return list; 
}); 

void main() { 
    var nested = [ 'a', 'w', ['e', ['f', new Object(), 'f'], 'g'], 't', 'e']; 
    print(concat(flatten(nested)); 
} 

Update:

alterantive concat, вдохновленный Greg Lowe (делать точно так же, как мой "большой" и его один, но еще более конденсируются):

concat(Iterable list) => list.fold([], (List xs, x) => xs..add(
    x is String && !xs.isEmpty && xs.last is String ? xs.removeLast() + x : x)); 

Вы можете комбинировать его и мои функции так, как вы хотите, они делают то же самое вещь.

2

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

List compress(List list) { 
    var sb = new StringBuffer(); 
    List result = []; 
    List compressRec(List list) { 
    for (var element in list) { 
     if (element is String) { 
     sb.write(element); 
     } else if (element is List) { 
      compressRec(list); 
     } else { 
     if (sb.isNotEmpty()) { 
      result.add(sb.toString()); 
      sb.clear(); 
     } 
     result.add(element); 
     } 
    } 
    } 
    compressRec(list) 
    if (sb.isNotEmpty()) { 
    result.add(sb.toString()); 
    } 
    return result; 
} 
Смежные вопросы