2016-09-01 3 views
6

Eine Sache, die ich in Perl 6 ist eine intersperse Funktion like Haskell has bisher verpasst haben, schreiben:Wie eine `intersperse` Funktion in Perl 6

Die intersperse Funktion nimmt ein Element und eine Liste und` streut dieses Element zwischen den Elementen der Liste.

z. dies:

intersperse <X Y>, (<a b>, <c d>, <e f>); 

... sollte diese Sequenz zurück:

<a b>, <X Y>, <c d>, <X Y>, <e f> 

Also habe ich versucht, es zu implementieren mich als eine benutzerdefinierte Funktion. Für eine maximale Wiederverwendbarkeit, es sollte:

  1. Unterstützung jeder Art von Objekt (einschließlich Liste und Nil) als Elemente.
  2. Ändern Sie nicht die Containerisierung von Elementen in irgendeiner Weise.
  3. Die innere Struktur der Elemente in keiner Weise abflachen oder anderweitig beeinträchtigen.
  4. Geben Sie eine Lazy-Sequenz zurück, wenn die Eingabeliste als Lazy-Sequenz angegeben ist, so dass sie für unendliche Sequenzen verwendet werden kann, wie in intersperse 42, 1..Inf.

Was ich mit so weit habe kommen, ist dies:

sub intersperse (\element, +list) { 
    ((element xx *) Z list).map(|*)[1..*] 
} 

Das heißt: Stufenlos das Element wiederholen setzt werden, ist es mit der Liste zip, dann map jedes Tupel zu slip verwenden um die durch die Zip-Datei hinzugefügte Verschachtelungsschicht zu entfernen, ohne die ursprünglichen Elemente zu verflachen, und dann einen Array-Index zu verwenden, um die führende Wiederholung des eingestreuten Elements zu entfernen.

es die Anforderungen erfüllt, 1-3, aber nicht mehr als 4, weil der Array-Index arbeitet mit Spannung (dh iteriert vollständig die Eingangssequenz und gibt dann eine nicht lazy List) und somit diese Funktion bewirkt, wenn gegeben aufzuhängen ein unendliche Sequenz.

Was wäre ein guter Weg, um diese Funktion zu implementieren, so dass sie alle 4 Anforderungen erfüllt?

+2

Inter schätzend. Irgendwie wie eine 'List'-Version von' Join'. –

Antwort

9

Ich bin nicht besonders glücklich mit den Lösungen, die ich habe kommen mit, aber hier gehen sie:

sub intersperse (\element, +list) { 
    map { ((element xx *) Z list).map(|*)[$_] }, 
     1..(list.is-lazy ?? Inf !! list.elems * 2 - 1); 
} 

sub intersperse (\element, +list) { 
    gather for list { 
     FIRST .take, next; 
     take slip element, $_; 
    } 
} 

sub intersperse (\element, +list) { 
    list.map({ slip element, $_ }) does role { 
     method iterator { 
      my \it = callsame; 
      it.pull-one; 
      it; 
     } 
    } 
} 

Vielleicht wird es dienen als Inspiration für jemand anderen, etwas Besseres zu finden ...

+0

Autsch, der erste macht es von "O (n)" in "O (n²)", oder? – smls

+0

Das 'Gather' /' Take' scheint jedoch ein guter Ansatz zu sein, daran hatte ich nicht gedacht. Ich glaube nicht, dass der Komma-Operator garantiert ein Sequenzpunkt ist, wie es in C ist, also würde ich wahrscheinlich diese Zeile so schreiben wie 'FIRST {take $ _; nächste} '. – smls

+0

Nun, ich würde den ersten Ansatz nicht empfehlen: Es war genau das, was ich entwickelt habe, damit Ihre ursprüngliche Idee funktioniert. Ich vermute, es könnte einen besseren Weg geben, aber es war mir nicht sofort klar; in Bezug auf den Komma-Operator sollte es sicher sein, da es von links nach rechts ausgewertet wird; Ich denke nicht, dass das irgendwo dokumentiert ist - wenn es nicht jemand tun sollte und fügen Sie einen entsprechenden Spectest hinzu. – Christoph

Verwandte Themen