Rimuovi i duplicati da una stringa


17

Ispirato a questa domanda StackOverflow senza pretese .

L'idea è semplice; data una stringa e un array di stringhe, rimuovi qualsiasi istanza di parole nell'array (ignorando il caso) dall'input String diverso dal primo, insieme a qualsiasi altro spazio bianco che può lasciare. Le parole devono corrispondere a parole intere nella stringa di input e non a parti di parole.

ad es. "A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat", ["cat", "mat"]dovrebbe produrre"A cat called matt sat on a mat and wore a hat A called matt sat on a and wore a hat"

Ingresso

  • L'input può essere preso come una stringa e una matrice di stringhe o una matrice di stringhe in cui la stringa di input è il primo elemento. Questi parametri possono essere in entrambi gli ordini.
  • La stringa di input non può essere considerata come un elenco di stringhe delimitate da spazi.
  • La stringa di input non avrà spazi iniziali, finali o consecutivi.
  • Tutti gli input conterranno solo caratteri [A-Za-z0-9] con l'eccezione della stringa di input che include anche spazi.
  • La matrice di input può essere vuota o contenere parole non presenti nella stringa di input.

Produzione

  • L'output può essere il valore restituito da una funzione o stampato su STDOUT
  • L'output deve essere nello stesso caso della stringa originale

Casi test

the blue frog lived in a blue house, [blue] -> the blue frog lived in a house
he liked to read but was filled with dread wherever he would tread while he read, [read] -> he liked to read but was filled with dread wherever he would tread while he
this sentence has no matches, [ten, cheese] -> this sentence has no matches
this one will also stay intact, [] -> this one will also stay intact
All the faith he had had had had no effect on the outcome of his life, [had] -> All the faith he had no effect on the outcome of his life
5 times 5 is 25, [5, 6] -> 5 times is 25
Case for different case, [case] -> Case for different
the letters in the array are in a different case, [In] -> the letters in the array are a different case
This is a test Will this be correct Both will be removed, [this,will] -> This is a test Will be correct Both be removed

Dato che si tratta di code golf, vince il conteggio di byte più basso!

Risposte:


9

R , 84 byte

function(s,w,S=el(strsplit(s," ")),t=tolower)cat(S[!duplicated(x<-t(S))|!x%in%t(w)])

Provalo online!

Meno di 100 byte in una sfida che non è anche ?

Spiegazione:

Dopo aver spezzato la stringa in parole, dobbiamo escludere quelli che lo sono

  1. duplicati e
  2. nel w

o in alternativa, girandolo sulla sua testa, mantenendo quelli che lo sono

  1. la prima occorrenza di una parola OR
  2. non dentro w.

duplicatedrestituisce ordinatamente gli indici logici di quelli che non sono la prima occorrenza, quindi !duplicated()restituisce gli indici di quelli che sono le prime occorrenze e x%in%wrestituisce gli indici logici per xquelli che sono presenti w. Neat.


6

Java 8, 117 110 byte

a->s->{for(String x:a)for(x="(?i)(.*"+x+".* )"+x+"( |$)(.*)";s.matches(x);s=s.replaceAll(x,"$1$3"));return s;}

Spiegazione:

Provalo online.

a->s->{                // Method with String-array and String parameters and String return
  for(String x:a)      //  Loop over the input-array
    for(x="(?i)(.*"+x+".* )"+x+"( |$)(.*)";
                       //   Regex to match
        s.matches(x);  //   Inner loop as long as the input matches this regex
      s=s.replaceAll(x,"$1$3")); 
                       //    Replace the regex-match with the 1st and 3rd capture groups
  return s;}           //  Return the modified input-String

Spiegazione aggiuntiva per la regex:

(?i)(.*"+x+".* )"+x+"( |$)(.*)   // Main regex to match:
(?i)                             //  Enable case insensitivity
    (                            //  Open capture group 1
     .*                          //   Zero or more characters
       "+x+"                     //   The input-String
            .*                   //   Zero or more characters, followed by a space
               )                 //  End of capture group 1
                "+x+"            //  The input-String again
                     (           //  Open capture group 2
                       |$        //   Either a space or the end of the String
                         )       //  End of capture group 2
                          (      //  Open capture group 3
                           .*    //   Zero or more characters
                             )   //  End of capture group 3

$1$3                             // Replace the entire match with:
$1                               //  The match of capture group 1
  $3                             //  concatted with the match of capture group 3

4

MATL , 19 18 byte

"Ybtk@kmFyfX<(~)Zc

Gli input sono: una matrice di celle di stringhe, quindi una stringa.

Provalo online! Oppure verifica tutti i casi di test .

Come funziona

"        % Take 1st input (implicit): cell array of strings. For each
  Yb     %   Take 2nd input (implicit) in the first iteration: string; or
         %   use the string from previous iteration. Split on spaces. Gives
         %   a cell array of strings
  tk     %   Duplicate. Make lowercase
  @k     %   Push current string from the array taken as 1st input. Make
         %   lowercase
  m      %   Membership: gives true-false array containing true for strings
         %   in the first input argument that equal the string in the second
         %   input argument
  F      %   Push false
  y      %   Duplicate from below: pushes the true-false array again
  f      %   Find: integer indices of true entries (may be empty)
  X<     %   Minimum (may be empty)
  (      %   Assignment indexing: write false in the true-false array at that
         %   position. So this replaces the first true (if any) by false
  ~      %   Logical negate: false becomes true, true becomes false
  )      %   Reference indexing: in the array of (sub)strings that was
         %   obtained from the second input, keep only those indicated by the
         %   (negated) true-false array
  Zc     %   Join strings in the resulting array, with a space between them
         % End (implicit). Display (implicit)

3

Perl 5 , 49 byte

@B=<>;$_=join$",grep!(/^$_$/xi~~@B&&$v{+lc}++),@F

Provalo online!

Salvataggio di 9 (!!) byte grazie a @TonHospel !


1
Questo sembra fallire per This is a test Will this be correct Both will be removed+ this will. Le seconde due parole vengono rimosse correttamente, ma per qualche motivo rimosse anche bela seconda dopo will.
Kevin Cruijssen,

1
@KevinCruijssen Hmmm, posso vedere perché questo sta accadendo in questo momento. Domani proverò a dare la giusta occhiata a pranzo, ma per ora ho risolto un costo di +4. Grazie per avermi fatto sapere!
Dom Hastings,

Per 49:@B=<>;$_=join$",grep!(/^$_$/xi~~@B&&$v{+lc}++),@F
Ton Hospel,

@TonHospel Ahh, ha trascorso un po 'di tempo a cercare di lcessere chiamato senza genitori. Eccezionale! E usare una regex contro l'array è molto meglio, grazie! Faccio fatica a ricordare tutti i tuoi consigli!
Dom Hastings,

2

Pyth, 27 byte

jdeMf!}r0eT@mr0dQmr0dPT._cz

Provalo online

Spiegazione

jdeMf!}r0eT@mr0dQmr0dPT._cz
                          z  Take the string input.
                       ._c   Get all the prefixes...
    f    eT@                 ... which end with something...
     !}         Q    PT      ... which is not in the input and the prefix...
       r0   mr0d mr0d        ... case insensitive.
jdeM                         Join the ends of each valid prefix.

Sono sicuro che i 10 byte per il controllo senza distinzione tra maiuscole e minuscole possono essere ridotti, ma non vedo come.


2

Stax , 21 byte CP437

åìøΓ²¬$M¥øHΘQä~╥ôtΔ♫╟

25 byte quando decompresso,

vjcm[]Ii<;e{vm_]IU>*Ciyj@

Il risultato è un array. L'output conveniente per Stax è un elemento per riga.

Esegui ed esegui il debug online!

Spiegazione

vj                           Convert 1st input to lowercase and split at spaces,
  c                          Duplicate at the main stack
   m                         Map array with the rest of the program 
                                 Implicitly output
    []I                      Get the first index of the current array element in the array
       i<                    Test 1: The first index is smaller than the iteration index
                                 i.e. not the first appearance
         ;                   2nd input
          {vm                Lowercase all elements
             _]I             Index of the current element in the 2nd input (-1 if not found)
                U>           Test 2: The index is non-negative
                                 i.e. current element is a member of the 2nd input
                  *C         If test 1 and test 2, drop the current element
                                 and go on mapping the next
                    iyj@     Fetch the corresponding element in the original input and return it as the mapped result
                                 This preserves the original case

2

Perl 6 , 49 byte

->$_,+w{~.words.grep:{.lcw».lc||!(%){.lc}++}}

Provalo

Allargato:

->              # pointy block lambda
  $_,           # first param 「$_」 (string)
  +w            # slurpy second param 「w」 (words)
{

  ~             # stringify the following (joins with spaces)

  .words        # split into words (implicit method call on 「$_」)

  .grep:        # take only the words we want

   {
     .lc        # lowercase the word being tested
               # is it not an element of
     w».lc      # the list of words, lowercased

     ||         # if it was one of the words we need to do a secondary check

     !          # Boolean invert the following
                # (returns true the first time the word was found)

     (
       %        # anonymous state Hash variable
     ){ .lc }++ # look up with the lowercase of the current word, and increment
   }
}

2

Perl 5 , 50 48 byte

Include +1per-p

Dare la stringa di destinazione seguita da ciascuna parola filtro su righe separate su STDIN:

perl -pe '$"="|";s%\b(@{[<>]})\s%$&x!$v{lc$1}++%iegx;chop';echo
This is a test Will this be correct Both will be removed
this
will
^D
^D

È chopnecessario solo per correggere lo spazio finale nel caso in cui l'ultima parola venga rimossa

Solo il codice:

$"="|";s%\b(@{[<>]})\s%$&x!$v{lc$1}++%iegx;chop

Provalo online!


1

JavaScript (ES6), 98 byte

s=>a=>s.split` `.filter(q=x=>(q[x=x.toLowerCase()]=eval(`/\\b${x}\\b/i`).test(a)<<q[x])<2).join` `

1

K4 , 41 byte

Soluzione:

{" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}

Esempi:

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat";("cat";"mat")]
"A cat called matt sat on a mat and wore a hat A called matt sat on a and wore a hat"

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["Case for different case";enlist "case"]
"Case for different"

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["the letters in the array are in a different case";enlist "In"]
"the letters in the array are a different case"

q)k){" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x}["5 times 5 is 25";(1#"5";1#"6")]
"5 times is 25"

Spiegazione:

Dividi su spazi bianchi, minuscoli entrambi gli input, cerca corrispondenze, rimuovi tutto tranne la prima occorrenza, unisci nuovamente la stringa.

{" "/:x_/y@>y:,/1_'&:'(_y)~/:\:_x:" "\:x} / the solution
{                                       } / lambda with implicit x & y args
                                  " "\:x  / split (\:) on whitespace " "
                                x:        / save result as x
                               _          / lowercase x
                          ~/:\:           / match (~) each right (/:), each left (\:)
                      (_y)                / lowercase y
                   &:'                    / where (&:) each ('), ie indices of matches
                1_'                       / drop first of each result
              ,/                          / flatten
            y:                            / save result as y
         y@>                              / descending indices (>) apply (@) to y
      x_/                                 / drop (_) from x
 " "/:                                    / join (/:) on whitespace " "

1

JavaScript (Node.js) , 75 byte

f=(s,a)=>a.map(x=>s=s.replace(eval(`/\\b${x}\\b */ig`),s=>i++?"":s,i=0))&&s

Provalo online!


1
Poiché questa non è una funzione ricorsiva, non è necessario includere il f=nel conteggio dei byte. È inoltre possibile salvare un byte valutando i parametri, sostituendoli (s,a)=>con s=>a=>e quindi chiamando la funzione con f(s)(a).
Shaggy,

@Shaggy sì, ma penso davvero al golf la definizione della funzione perché l'accordo principale è giocare a golf sul corpo. ma grazie, questo è un buon consiglio :)
DanielIndie,

1

JavaScript ES6, 78 byte

f=(s,a,t={})=>s.split` `.filter(w=>a.find(e=>w==e)?(t[w]?0:t[w]=1):1).join` `

Come funziona:

f=(s,a,t={})=> // Function declaration; t is an empty object by default
s.split` ` // Split the string into an array of words
.filter(w=> // Declare a function that, if it returns false, will delete the word
  a.find(e=>w==e) // Returns undeclared (false) if the word isn't in the list
  ?(t[w]?0 // If it is in the list and t[w] exists, return 0 (false)
    :t[w]=1) // Else make t[w] exist and return 1 (true)
  :1) // If the word isn't in the array, return true (keep the word for sure)
.join` ` // Rejoin the string

2
Benvenuti in PPCG! Dal momento che non si utilizza il nome della funzione fper una chiamata ricorsiva, anche una funzione senza nome sarebbe un invio valido, quindi è possibile salvare due byte rilasciando il f=.
Martin Ender,

Benvenuti in PPCG! Purtroppo questo fallisce quando sono coinvolti diversi casi.
Shaggy,

Se non fosse per quello, potresti arrivare a 67 byte
Shaggy,

@MartinEnder Grazie per il suggerimento!
Ian,

@Shaggy utilizzando l'array di input come oggetto è un'idea interessante a cui non avevo pensato. Proverò a risolvere il problema del caso.
Ian,

0

PowerShell v3 o successivo, 104 byte

Param($s,$w)$w|?{$_-and$s-match($r="\b$_(?: |$)")}|%{$h,$t=$s-split$r;$s="$h$($Matches.0)$(-join$t)"};$s

Al costo di un byte, può essere eseguito in PS 2.0 sostituendolo $Matches.0con $Matches[0].

Versione lunga:

Param($s, $w)
$w | Where-Object {$_ -and $s -match ($r = "\b$_(?: |$)")} |    # Process each word in the word list, but only if it matches the RegEx (which will be saved in $r).
    ForEach-Object {                                            # \b - word boundary, followed by the word $_, and either a space or the end of the string ($)
        $h, $t = $s -split $r                                   # Split the string on all occurrences of the word; the first substring will end up in $h(ead), the rest in $t(ail) (might be an array)
        $s = "$h$($Matches.0)$(-join $t)"                       # Create a string from the head, the first match (can't use the word, because of the case), and the joined tail array
    }
$s                                                              # Return the result

Usa
Save as qualunque.ps1 e chiama con la stringa e le parole come argomenti. Se è necessario passare più di una parola, le parole devono essere racchiuse in @ ():

.\Whatever.ps1 -s "A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat" -w @("cat", "mat")

Alternativa senza file (può essere incollata direttamente in una console PS):
salva lo script come ScriptBlock (all'interno di parentesi graffe) in una variabile, quindi chiama il suo metodo Invoke () o usalo con Invoke-Command:

$f={Param($s,$w)$w|?{$_-and$s-match($r="\b$_(?: |$)")}|%{$h,$t=$s-split$r;$s="$h$($Matches.0)$(-join$t)"};$s}
$f.Invoke("A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat", @("cat", "mat"))
Invoke-Command -ScriptBlock $f -ArgumentList "A cat called matt sat on a mat and wore a hat A cat called matt sat on a mat and wore a hat", @("cat", "mat")

0

Javascript, 150 byte

s=(x, y)=>{let z=new Array(y.length).fill(0);let w=[];for(f of x)(y.includes(f))?(!z[y.indexOf(f)])&&(z[y.indexOf(f)]=1,w.push(f)):w.push(f);return w}

Oltre ai problemi con il golf (dai un'occhiata alle altre soluzioni JS per alcuni suggerimenti lì), questo prende il primo input come un array di parole e genera un array di parole che non è consentito dalle specifiche della sfida. Inoltre fallisce quando sono coinvolti diversi casi.
Shaggy,

@Shaggy "L'output può essere il valore restituito da una funzione" Sembra che restituisca un valore dalla funzione?
aimorris,

0

Pulito , 153 142 138 134 byte

import StdEnv,StdLib,Text
@ =toUpperCase
$s w#s=split" "s
=join" "[u\\u<-s&j<-[0..]|and[i<>j\\e<-w,i<-drop 1(elemIndices(@e)(map@s))]]

Provalo online!

Definisce la funzione $ :: String [String] -> String, praticamente facendo ciò che la sfida descrive. Trova e rimuove ogni ricorrenza dopo la prima, per ogni parola target.


0

Retina, 46 37 byte

+i`(^|,)((.+),.*\3.* )\3( |$)
$2
.*,

-14 byte grazie a @Neil e +5 byte per una correzione di bug.

Input nel formato word1,word2,word3,sentence, perché non sono sicuro di come disporre di input multilinea (in cui gli input vengono utilizzati in modo diverso) ..

Spiegazione:

Provalo online.

+i`(^|,)((.+),.*\3.* )\3( |$)   Main regex to match:
+i`                              Enable case insensitivity
   (^|,)                          Either the start of the string, or a comma
        (                         Open capture group 2
         (                         Open capture group 3
          .+                        1 or more characters
            )                      Close capture group 3
             ,                     A comma
              .*                   0 or more characters
                \3                 The match of capture group 3
                  .*               0 or more characters, followed by a space
                     )            Close capture group 2
                      \3          The match of capture group 2 again
                        ( |$)     Followed by either a space, or it's the end of the string
$2                              And replace everything with:
                                 The match of capture group 2

.*,                             Then get everything before the last comma (the list)
                                 and remove it (including the comma itself)

1
Come scritto, puoi semplificare la prima riga +i`((.+),.*\2.* )\2( |$)e la seconda, $1ma noto che il tuo codice non riesce often,he intended to keep ten geesecomunque.
Neil,

@Neil Grazie per il golf -14 e risolto il bug con +1.
Kevin Cruijssen,

... tranne che questo ora fallisce in uno dei casi di test originali ...
Neil,

@Neil Ah oops .. Risolto nuovamente per +4 byte.
Kevin Cruijssen,

Bene, la buona notizia è che penso che tu possa usare al \bposto di (^|,), ma la cattiva notizia è che penso che tu abbia bisogno \b\3\b(non ho ancora ideato un caso di test adatto).
Neil,

0

Rosso , 98 byte

func[s w][foreach v w[parse s[thru[any" "v ahead" "]any[to remove[" "v ahead[" "| end]]| skip]]]s]

Provalo online!

f: func [s w][ 
    foreach v w [                   ; for each string in the array
        parse s [                   ; parse the input string as follows:
            thru [                  ; keep everything thru: 
                any " "             ; 0 or more spaces followed by
                v                   ; the current string from the array followed by
                ahead " "           ; look ahead for a space
            ]
            any [ to remove [       ; 0 or more: keep to here; then remove: 
                " "                 ; a space followed by 
                v                   ; the current string from the array
                ahead [" " | end]]  ; look ahead for a space or the end of the string
            | skip                  ; or advance the input by one 
            ]
        ]
    ]
    s                               ; return the processed string 
]

0

Buccia , 13 byte

wüöVËm_Ṗ3+⁰ew

Accetta un elenco di stringhe e una singola stringa come argomenti, in questo ordine. Presuppone che l'elenco sia privo di duplicati. Provalo online!

Spiegazione

wüöVËm_Ṗ3+⁰ew  Inputs: list of strings L (explicit, accessed with ⁰), string S (implicit).
               For example, L = ["CASE","for"], s = "Case for a different case".
            w  Split S on spaces: ["Case","for","a","different","case"]
 ü             Remove duplicates wrt an equality predicate.
               This means that a function is called on each pair of strings,
               and if it returns a truthy value, the second one is removed.
  öVËm_Ṗ3+⁰e    The predicate. Arguments are two strings, say A = "Case", B = "case".
           e    Put A and B into a list: ["Case","case"]
         +⁰     Concatenate with L: ["CASE","for","Case","case"]
       Ṗ3       All 3-element subsets: [["CASE","for","Case"],["CASE","for","case"],
                                        ["CASE","Case","case"],["for","Case","case"]]
  öV            Does any of them satisfy this:
    Ë            All strings are equal
     m_          after converting each character to lowercase.
                In this case, ["CASE","Case","case"] satisfies the condition.
               Result: ["Case","for","a","different"]
w              Join with spaces, print implicitly.

0

Min , 125 byte

=a () =b a 1 get =c a 0 get " " split
(:d (b d in?) ((c d in?) (d b append #b) unless) (d b append #b) if) foreach
b " " join

L'input è quotnello stack con input String come primo elemento e una quotdelle stringhe duplicate come secondo elemento, ovvero

("this sentence has no matches" ("ten" "cheese"))

0

Python 3 , 168 byte

def f(s,W):
 s=s.split(" ");c={w:0for w in W}
 for w in W: 
  for i,v in enumerate(s):
   if v.lower()==w.lower():
    c[w]+=1
    if c[w]>1:s.pop(i)
 return" ".join(s)

Provalo online!


0

AWK , 120 byte

NR%2{for(;r++<NF;)R[tolower($r)]=1}NR%2==0{for(;i++<NF;$i=$(i+s))while(R[x=tolower($(i+s))])U[x]++?++s:i++;NF-=s}NR%2==0

Provalo online!

La parte "rimuovi spazi bianchi" lo ha reso un po 'più impegnativo di quanto pensassi all'inizio. Impostare un campo su"" , rimuove un campo, ma lascia un separatore aggiuntivo.

Il collegamento TIO ha 28 byte extra per consentire più voci.

L'input è dato su 2 righe. La prima riga è l'elenco di parole e la seconda è la "frase". Si noti che "parola" e "parola" non sono considerati identici alla punteggiatura allegata. Avere requisiti di punteggiatura renderebbe probabilmente questo un problema ancora più divertente .


0

Rubino , 63 61 60 59 byte

->s,w{w.any?{|i|s.sub! /\b(#{i}\b.*) #{i}\b/i,'\1'}?redo:s}

Provalo online!

Una versione più breve che fa distinzione tra maiuscole e minuscole e non riesce ~ ogni 10 15 volte a causa della casualità (37 byte)

->s,w{s.uniq{|i|w.member?(i)?i:rand}}

0

Python 2 , 140 byte

from re import*
p='\s?%s'
S,A=input()
for a in A:S=sub(p%a,lambda s:s.end()==search(p%a,S,flags=I).end()and s.group()or'',S,flags=I)
print S

Provalo online!

Spiegazione:

re.sub(..)può prendere come argomento una funzione anziché una stringa di sostituzione. Quindi qui abbiamo qualche lambda di fantasia. La funzione viene chiamata per ogni occorrenza del modello e un oggetto viene passato a questa funzione - matchobject. Questo oggetto contiene informazioni sull'occorrenza fondata. Sono interessato all'indice di questo evento, che può essere recuperato da start()oend() funzione. L'ultimo è più breve, quindi viene utilizzato.

Per escludere la sostituzione della prima occorrenza della parola, ho usato un'altra funzione di ricerca regex per ottenere esattamente una prima e poi confrontare gli indici, usando lo stesso end()

Bandiera re.I è la versione breve dire.IGNORECASES

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.