Видаліть дублікати з рядка


17

Натхненний цим невимогливим питанням StackOverflow .

Ідея проста; задавши String і масив Strings, видаліть будь-які екземпляри слів з масиву (ігноруючи регістр) з вхідного рядка, відмінного від першого, разом з будь-яким додатковим пробілом, який це може залишити. Слова повинні відповідати цілим словам у вхідному рядку, а не частинам слів.

наприклад, "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"

Вхідні дані

  • Введення можна сприймати як String, так і масив Strings або масив Strings, де вхідний String є першим елементом. Ці параметри можуть бути в будь-якому порядку.
  • Рядок введення може не сприйматися як список рядків з обмеженим пробілом.
  • У рядку введення не буде провідної, кінцевої чи послідовної пробілів.
  • Весь вхід буде містити символи [A-Za-z0-9] за винятком рядка введення, що включає також пробіли.
  • Вхідний масив може бути порожнім або містити слова, які не є в ряді введення.

Вихідні дані

  • Вихід може бути або поверненим значенням функції, або надрукованим в STDOUT
  • Вихід повинен бути в тому ж випадку, що і вихідний рядок

Тестові справи

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

Оскільки це код гольфу, виграє найменший байт!

Відповіді:


9

R , 84 байти

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

Спробуйте в Інтернеті!

Менше ніж 100 байт на виклик , що це також не ?

Пояснення:

Після розбиття рядка на слова, нам потрібно виключити ті, що є

  1. дублікати та
  2. в w

або ж, повертаючи це на голову, зберігаючи ті, що є

  1. перше виникнення слова АБО
  2. не в w.

duplicatedакуратно повертає логічні індекси тих, хто не є першим явищем, тому !duplicated()повертає індекси тих, хто є першими подіями, і x%in%wповертає логічні показники для xтих, хто знаходиться w. Акуратний.


6

Java 8, 117 110 байт

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

Пояснення:

Спробуйте в Інтернеті.

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

Додаткове пояснення для регулярного вираження:

(?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 байт

"Ybtk@kmFyfX<(~)Zc

Вхідними даними є: масив комірок рядків, потім рядок.

Спробуйте в Інтернеті! Або перевірити всі тестові випадки .

Як це працює

"        % 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 байт

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

Спробуйте в Інтернеті!

Збережено 9 (!!) байтів завдяки @TonHospel !


1
Здається, це не вдається для This is a test Will this be correct Both will be removed+ this will. Другі два слова правильно видалено, але beпісля другого він також willчомусь видалено .
Kevin Cruijssen

1
@KevinCruijssen Хм, я бачу, чому це відбувається в даний момент. Я спробую завтра добре поглянути на обід, але поки що я виправдався ціною +4. Дякую що дали мені знати!
Дом Гастінгс

Для 49:@B=<>;$_=join$",grep!(/^$_$/xi~~@B&&$v{+lc}++),@F
Євангеліє Тон

@TonHospel Ах, провів деякий час, намагаючись lcзателефонувати без паренів. Дивовижно! І використовувати регулярний вираз проти масиву набагато краще, Дякую! Я намагаюся згадати всі ваші поради!
Дом Гастінгс

2

Піт, 27 байт

jdeMf!}r0eT@mr0dQmr0dPT._cz

Спробуйте в Інтернеті

Пояснення

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.

Я впевнений, що 10 байтів для перевірки нечутливості до випадків можна зменшити, але я не розумію, як.


2

Stax , 21 байт CP437

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

25 байт при розпакуванні,

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

Результат - масив. Зручний вихід для Stax - один елемент на рядок.

Запуск та налагодження в Інтернеті!

Пояснення

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 байт

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

Перевірте це

Розширено:

->              # 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 байт

Включає +1для-p

Надайте цільовий рядок, після якого кожне слово фільтра в окремих рядках на 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

Це chopпотрібно лише для фіксації пробілу у випадку, якщо останнє слово буде видалено

Просто код:

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

Спробуйте в Інтернеті!


1

JavaScript (ES6), 98 байт

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

1

К4 , 41 байт

Рішення:

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

Приклади:

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"

Пояснення:

Розділіть пробіл, малі і обидва входи, шукайте збіги, видаліть усі, крім першої зустрічі, з'єднайте рядок назад разом.

{" "/: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 байт

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

Спробуйте в Інтернеті!


1
Оскільки це не рекурсивна функція, вам не потрібно включати число f=в байт. Ви також можете зберегти байти з вироблення параметрів, замінюючи (s,a)=>з , s=>a=>а потім викликати функцію з f(s)(a).
Кудлатий

@Shaggy так, але я дуже заперечую про те, щоб визначити функцію гольфу, оскільки головна справа - це гольф на тілі. але ТНХ ось хороший рада :)
DanielIndie

1

JavaScript ES6, 78 байт

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

Як це працює:

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
Ласкаво просимо до PPCG! Оскільки ви не використовуєте ім'я функції fдля рекурсивного виклику, неназвана функція також буде дійсним поданням, тому ви можете зберегти два байти, скинувши f=.
Мартін Ендер

Ласкаво просимо до PPCG! На жаль, це не вдається, коли залучаються різні справи.
Кудлатий

Якби не це, ви могли звести це до 67 байт
Shaggy

@MartinEnder Дякую за пораду!
Ян

@Shaggy, що використовує вхідний масив як об’єкт - цікава ідея, про яку я не думав. Я спробую виправити випадок проблеми.
Ян

0

PowerShell v3 або новішої версії, 104 байти

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

Ціною одного байта він може працювати в PS 2.0 шляхом заміни $Matches.0на$Matches[0] .

Довга версія:

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

Використовуйте
Зберегти як Wwhat.ps1 і зателефонувати за допомогою рядка та слів як аргументів. Якщо потрібно передати більше одного слова, слова потрібно загорнути в @ ():

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

Альтернатива без файлу (може бути вставлена ​​безпосередньо в консоль PS):
збережіть скрипт як ScriptBlock (всередині фігурних дужок) у змінній, а потім викликайте його метод Invoke () або використовуйте його з 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 байт

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}

Окрім проблем із гольфу (подивіться на інші рішення JS для деяких порад там), це перше введення сприймає як масив слів та видає масив слів, який заборонений специфікацією виклику. Він також провалюється, коли залучаються різні справи.
Кудлатий

@Shaggy "Вихідним може бути або повернене значення функції" Це виглядає так, що він повертає значення функції?
aimorris

0

Чисто , 153 142 138 134 байт

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

Спробуйте в Інтернеті!

Визначає функцію $ :: String [String] -> String, майже буквально виконуючи те, що описується завданням. Він знаходить і видаляє кожне виникнення після першого, для кожного цільового слова.


0

Сітківка, 46 37 байт

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

-14 байт завдяки @Neil та +5 байт для виправлення помилок.

Введіть у форматі word1,word2,word3,sentence, тому що я не впевнений, як мати багаторядковий ввід (де входи використовуються по-різному) ..

Пояснення:

Спробуйте в Інтернеті.

+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
Як написано, ви можете спростити перший рядок до +i`((.+),.*\2.* )\2( |$)другого, $1але я помічаю, що ваш код often,he intended to keep ten geeseвсе одно виходить з ладу .
Ніл

@Neil Дякуємо за -14 гольф і виправили помилку +1.
Кевін Кройсейсен

... за винятком того, що зараз це не вдається в одному з оригінальних тестових випадків ...
Ніл

@Neil Ah oops .. Виправлено знову на +4 байти.
Кевін Кройсейсен

Що ж, хорошими новинами є те, що я думаю, що ви можете використовувати їх \bзамість (^|,), але погані новини - я думаю, вам це потрібно \b\3\b(все ще не придумали відповідний тестовий випадок).
Ніл

0

Червоний , 98 байт

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

Спробуйте в Інтернеті!

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

Лушпиння , 13 байт

wüöVËm_Ṗ3+⁰ew

В якості аргументів приймає список рядків і одного рядка в цьому порядку. Передбачає, що список не містить дублікатів. Спробуйте в Інтернеті!

Пояснення

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

Мінімум , 125 байт

=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

Введення знаходиться quotв стеці з вхідним рядком як першим елементом, а quotз повторюваних рядків як другим елементом, тобто

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


0

AWK , 120 байт

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

Спробуйте в Інтернеті!

Частина "видалити пробіли" зробила це трохи складніше, ніж я думав спочатку. Якщо встановити поле "", видаляє поле, але залишає додатковий роздільник.

Посилання TIO має 28 додаткових байтів, щоб дозволити кілька записів.

Введення подано через 2 рядки. Перший рядок - це список слів, а другий - «речення». Зауважте, що "слово" та "слово" не вважаються ідентичними, як і в доданому розділовому знаку. Наявність пунктуаційних вимог, ймовірно, зробить це ще більш цікавою проблемою.



0

Пітон 2 , 140 байт

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

Спробуйте в Інтернеті!

Пояснення:

re.sub(..)може взяти за аргумент функцію замість заміни рядка. Отже, тут у нас є кілька фантазійних лямбда. Функція викликається для кожного виникнення шаблону, і один об'єкт передається цій функції - matchobject. Цей об'єкт має інформацію про обґрунтовану появу Мене цікавить індекс цієї появи, який можна отримати start()або end()функціонувати. Пізніший коротший, тому його використовують.

Щоб виключити заміну першого виникнення слова, я використовував іншу функцію пошуку регулярних виразів, щоб отримати точно фіксацію одного, а потім порівняти індекси, використовуючи той самий end()

Прапор re.I- це коротка версіяre.IGNORECASES

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.