Hapus duplikat dari sebuah String

17

Terinspirasi oleh pertanyaan StackOverflow sederhana ini .

Idenya sederhana; diberi sebuah String dan sebuah array dari Strings, hapus setiap instance kata dalam array (abaikan case) dari String input selain yang pertama, bersama dengan spasi kosong apa pun yang tersisa. Kata-kata harus cocok dengan seluruh kata dalam String input, dan bukan bagian dari kata-kata.

misalnya "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"]harus output"A cat called matt sat on a mat and wore a hat A called matt sat on a and wore a hat"

Memasukkan

  • Input dapat diambil sebagai String, dan array dari Strings atau array dari Strings di mana String input adalah elemen pertama. Parameter ini bisa dalam urutan apa pun.
  • String input tidak dapat diambil sebagai daftar String yang dibatasi ruang.
  • String input tidak akan memiliki spasi memimpin, tertinggal atau berurutan.
  • Semua input hanya akan berisi karakter [A-Za-z0-9] dengan pengecualian dari String input juga termasuk spasi.
  • Array input mungkin kosong atau mengandung kata-kata yang tidak ada dalam String input.

Keluaran

  • Output dapat berupa nilai balik dari suatu fungsi, atau dicetak ke STDOUT
  • Output harus dalam kasus yang sama dengan String asli

Uji kasus

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

Karena ini adalah kode golf, jumlah byte terendah menang!

Luke Stevens
sumber

Jawaban:

9

R , 84 byte

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

Cobalah online!

Kurang dari 100 byte pada tantangan yang tidak juga ?

Penjelasan:

Setelah kami memecah string menjadi kata-kata, kita perlu mengecualikan mereka yang

  1. duplikat dan
  2. di w

atau sebagai alternatif, memutar kepalanya, menjaga yang ada

  1. kemunculan pertama kata OR
  2. tidak w.

duplicated rapi mengembalikan indeks logis dari mereka yang bukan kejadian pertama, jadi !duplicated() mengembalikan indeks dari mereka yang merupakan kejadian pertama, dan x%in%wmengembalikan indeks logis untuk xmereka yang berada di w. Rapi.

Giuseppe
sumber
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;}

Penjelasan:

Cobalah 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

Penjelasan tambahan untuk 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
Kevin Cruijssen
sumber
4

MATL , 19 18 byte

"Ybtk@kmFyfX<(~)Zc

Inputnya adalah: array sel string, lalu string.

Cobalah online! Atau verifikasi semua kasus uji .

Bagaimana itu bekerja

"        % 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)
Luis Mendo
sumber
3

Perl 5 , 49 byte

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

Cobalah online!

Disimpan 9 (!!) byte berkat @TonHospel !

Dom Hastings
sumber
1
Ini tampaknya gagal untuk This is a test Will this be correct Both will be removed+ this will. Dua kata kedua dihapus dengan benar, tetapi juga menghapus besetelah kata kedua willkarena beberapa alasan.
Kevin Cruijssen
1
@KevinCruijssen Hmmm, saya bisa melihat mengapa itu terjadi saat ini. Saya akan mencoba dan melihat makan siang dengan benar besok, tetapi saya telah memperbaiki untuk saat ini dengan biaya +4. Terima kasih telah memberi tahu saya!
Dom Hastings
Untuk 49:@B=<>;$_=join$",grep!(/^$_$/xi~~@B&&$v{+lc}++),@F
Ton Hospel
@TonHospel Ahh, menghabiskan beberapa waktu mencoba lcdipanggil tanpa orangtua. Luar biasa! Dan menggunakan regex terhadap array jauh lebih baik, Terima kasih! Saya kesulitan mengingat semua tips Anda!
Dom Hastings
2

Pyth, 27 byte

jdeMf!}r0eT@mr0dQmr0dPT._cz

Cobalah online

Penjelasan

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.

Saya yakin 10 byte untuk pemeriksaan case sensitive dapat dikurangi, tapi saya tidak mengerti caranya.


sumber
2

Stax , 21 byte CP437

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

25 byte saat dibongkar,

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

Hasilnya adalah sebuah array. Output yang nyaman untuk Stax adalah satu elemen per baris.

Jalankan dan debug online!

Penjelasan

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
Weijun Zhou
sumber
2

Perl 6 , 49 byte

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

Menguji

Diperluas:

->              # 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
   }
}
Brad Gilbert b2gills
sumber
2

Perl 5 , 50 48 byte

Termasuk +1untuk-p

Berikan string target diikuti oleh setiap kata filter pada baris terpisah di 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

Itu chop hanya diperlukan untuk memperbaiki ruang tambahan dalam kasus kata terakhir akan dihapus

Hanya kode:

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

Cobalah online!

Ton Hospel
sumber
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` `
Produksi ETH
sumber
1

K4 , 41 byte

Larutan:

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

Contoh:

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"

Penjelasan:

Berpisah di ruang putih, huruf kecil kedua input, cari yang cocok, hapus semua kecuali kejadian pertama, gabungkan string kembali bersama.

{" "/: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 " "
streetster
sumber
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

Cobalah online!

DanielIndie
sumber
1
Karena ini bukan fungsi rekursif, Anda tidak perlu memasukkan f=dalam jumlah byte Anda. Anda juga dapat menyimpan byte dengan mencari parameter, mengganti (s,a)=>dengan s=>a=>dan memanggil fungsi f(s)(a).
Shaggy
@ Shaggy ya, tapi saya benar-benar keberatan tentang golf definisi fungsi karena yang paling utama adalah golf tubuh. tapi itu tip yang bagus :)
DanielIndie
1

JavaScript ES6, 78 Bytes

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

Bagaimana itu bekerja:

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
Ian
sumber
2
Selamat datang di PPCG! Karena Anda tidak menggunakan nama fungsi funtuk panggilan rekursif, fungsi yang tidak disebutkan namanya juga akan menjadi pengiriman yang valid, sehingga Anda dapat menyimpan dua byte dengan menjatuhkan f=.
Martin Ender
Selamat datang di PPCG! Sayangnya ini gagal ketika berbagai kasus terlibat.
Shaggy
Jika bukan karena itu, Anda bisa mendapatkan ini hingga 67 byte
Shaggy
@ MartinEnder Terima kasih atas tipnya!
Ian
@ Shaggy menggunakan input array sebagai objek adalah ide menarik yang tidak pernah saya pikirkan. Saya akan mencoba dan memperbaiki masalah kasing.
Ian
0

PowerShell v3 atau lebih baru, 104 byte

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

Dengan biaya satu byte, itu dapat berjalan di PS 2.0 dengan mengganti $Matches.0dengan $Matches[0].

Versi panjang:

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

Gunakan
Simpan sebagai Apapun.ps1 dan panggil dengan string dan kata-kata sebagai argumen. Jika lebih dari satu kata harus dilewatkan, kata-kata tersebut harus dibungkus @ ():

.\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")

Alternatif tanpa file (dapat disisipkan langsung ke konsol PS):
Simpan skrip sebagai ScriptBlock (di dalam kurung kurawal) dalam variabel, lalu panggil metode Invoke (), atau gunakan dengan 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")
pengguna314159
sumber
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}
aimorris
sumber
Selain masalah dengan bermain golf (lihat solusi JS lainnya untuk beberapa tips di sana), ini mengambil input pertama sebagai susunan kata dan menghasilkan susunan kata yang tidak diizinkan oleh spec tantangan. Ini juga gagal ketika berbagai kasus terlibat.
Shaggy
@Shaggy "Outputnya bisa berupa nilai pengembalian dari suatu fungsi" Ini sepertinya mengembalikan nilai dari fungsi?
aimorris
0

Bersih , 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))]]

Cobalah online!

Menentukan fungsi $ :: String [String] -> String, cukup banyak melakukan apa yang digambarkan tantangan. Ia menemukan dan menghapus setiap kemunculan setelah yang pertama, untuk setiap kata target.

Suram
sumber
0

Retina, 46 37 byte

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

-14 byte terima kasih kepada @Neil , dan +5 byte untuk perbaikan bug.

Input dalam format word1,word2,word3,sentence, karena saya tidak yakin bagaimana cara input multi-line (di mana input digunakan secara berbeda) ..

Penjelasan:

Cobalah 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)
Kevin Cruijssen
sumber
1
Seperti yang tertulis, Anda dapat menyederhanakan baris pertama +i`((.+),.*\2.* )\2( |$)dan yang kedua $1tetapi saya perhatikan bahwa kode Anda gagal often,he intended to keep ten geese.
Neil
@Neil Terima kasih untuk golf -14, dan perbaiki bug dengan +1.
Kevin Cruijssen
... kecuali bahwa ini sekarang gagal pada salah satu kasus uji asli ...
Neil
@Neil Ah oops .. Diperbaiki lagi untuk +4 byte.
Kevin Cruijssen
Yah, kabar baiknya adalah saya pikir Anda bisa menggunakan \balih-alih (^|,), tapi kabar buruknya adalah saya pikir Anda perlu \b\3\b(belum menemukan test case yang cocok).
Neil
0

Merah , 98 byte

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

Cobalah 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 
]
Galen Ivanov
sumber
0

Sekam , 13 byte

wüöVËm_Ṗ3+⁰ew

Mengambil daftar string dan string tunggal sebagai argumen, dalam urutan ini. Mengasumsikan bahwa daftar tersebut bebas duplikat. Cobalah online!

Penjelasan

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.
Zgarb
sumber
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

Input quotpada stack dengan String input sebagai elemen pertama, dan a quotdari string duplikat sebagai elemen kedua, yaitu

("this sentence has no matches" ("ten" "cheese"))
Panda0nEarth
sumber
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)

Cobalah online!

Trelzevir
sumber
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

Cobalah online!

Bagian "hapus spasi" membuat ini sedikit lebih menantang daripada yang saya pikirkan. Mengatur bidang ke"" , menghapus bidang, tetapi meninggalkan pemisah tambahan.

TIO Link memiliki 28 byte tambahan untuk memungkinkan banyak entri.

Input diberikan lebih dari 2 baris. Baris pertama adalah daftar kata-kata dan yang kedua adalah "kalimat". Perhatikan bahwa "kata" dan "kata," tidak dianggap sama dengan tanda baca terlampir. Memiliki persyaratan tanda baca kemungkinan akan menjadikan masalah ini lebih menyenangkan .

Robert Benson
sumber
0

Ruby , 63 61 60 59 byte

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

Cobalah online!

Versi lebih pendek yang peka dan gagal ~ setiap 10 15 kali karena keacakan (37 byte)

->s,w{s.uniq{|i|w.member?(i)?i:rand}}
Asone Tuhid
sumber
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

Cobalah online!

Penjelasan:

re.sub(..)dapat mengambil sebagai argumen fungsi alih-alih string pengganti. Jadi di sini kita punya beberapa lambda mewah. Fungsi dipanggil untuk setiap kemunculan pola dan satu objek diteruskan ke fungsi ini - matchobject. Objek ini memiliki informasi tentang kejadian yang ditemukan. Saya tertarik pada indeks kejadian ini, yang dapat diambil oleh start()atau end()fungsinya. Yang terakhir lebih pendek sehingga digunakan.

Untuk mengecualikan penggantian kemunculan kata pertama, saya menggunakan fungsi pencarian regex lain untuk mendapatkan yang tepat dan membandingkan indeks, menggunakan yang sama end()

Bendera re.Iadalah versi pendek darire.IGNORECASES

Possum Mati
sumber