Count occurences of a set in a list

15

1

Given a non-empty set of strings and a list of strings, find out how many times the set occurs in the list, i.e. how many times you could create the set with items from the list. Every element from the list can only be used once.

Hint: a set is an unordered list of unique items.

Default input/output rules apply.

No external libraries allowed. Compiler/Interpreter standard libs are okay. This is code golf, so shortest solution counts.


Test cases:

["apple", "banana"], ["apple", "pear", "apple", "banana", "banana"] => 2

["apple", "banana"], ["apple", "pear", "apple", "banana", "apple"] => 1

["apple", "banana", "pear"], ["apple", "banana", "kiwi", "apple"] => 0

["coconut"], [] => 0

EDIT: removed a sentence stating that the input params are defined in local scope. This contradicts the default IO rules linked above.

Hubert Grzeskowiak

Posted 2017-04-20T18:36:31.220

Reputation: 239

Yes that clarifies it. However I am a little hung up on the third sentence. What do you mean by "doesn't handle objects"? – Post Rock Garf Hunter – 2017-04-20T18:45:57.083

@WheatWizard some languages are not object-oriented and don't know the concept of comparing arbitrary objects. – Hubert Grzeskowiak – 2017-04-20T18:47:00.090

1You should probably change that to object-oriented because every language I am aware of does handle objects of some type even if objects are a closed class. I should also point out that there are a good deal of languages that also cannot handle strings at all. – Post Rock Garf Hunter – 2017-04-20T18:49:04.753

@WheatWizard okay, updated description. That paragraph was meant for languages such as C, Assembler or Maple. – Hubert Grzeskowiak – 2017-04-20T18:59:26.463

What languages are object oriented? What should they use if not strings? I think the easiest thing would be to restrict to just strings. Or, alternatively, only integers. See this advice on using the simplest type that suffices.

– xnor – 2017-04-20T19:23:38.750

Good point, @xnor. updated. I think the solutions so far are all handling strings just fine, so this won't invalidate any. – Hubert Grzeskowiak – 2017-04-20T19:27:16.127

@AdmBorkBork nope! will add another test for that. – Hubert Grzeskowiak – 2017-04-20T19:42:16.420

The set is non-empty. The list can be empty. – Hubert Grzeskowiak – 2017-04-20T19:45:28.463

OK, I would suggest to explicitly add that. Like "Given a non-empty set of strings and a potentially-empty list of strings" or similar, because as it's currently written my brain reads it as both the set and the list are non-empty. – AdmBorkBork – 2017-04-20T19:47:02.757

For future reference, I'll also direct you to the Sandbox where you can post challenges, get meaningful feedback, and tweak them before they're posted to main.

– AdmBorkBork – 2017-04-20T19:47:59.107

@AdmBorkBork thanks. much appreciated. – Hubert Grzeskowiak – 2017-04-20T19:48:37.067

Related: Three fruit pies

– xnor – 2017-04-20T21:50:13.097

Answers

12

Python, 30 bytes

lambda s,l:min(map(l.count,s))

Try it online!

ovs

Posted 2017-04-20T18:36:31.220

Reputation: 21 408

Nice one. Didn't think about using map. You can save a little by using print instead of defining a lambda BTW. – Hubert Grzeskowiak – 2017-04-20T19:18:03.263

1@HubertGrzeskowiak Changing the lambda to a print brings the byte count up to 37 because of the two input()s required. – Post Rock Garf Hunter – 2017-04-20T20:49:52.950

@WheatWizard as stated in the challenge, consider the inputs defined in local scope. You are NOT required to have the inputs explicitly defined, e.g. as function params or user inputs. – Hubert Grzeskowiak – 2017-04-21T05:45:36.300

@HubertGrzeskowiak if there is no good reason for it, you should not overwrite our defaults for taking input and output and our defaults for codegolf submissions

– ovs – 2017-04-21T06:05:56.507

@ovs oh, I wasn't aware of that post. Thanks. – Hubert Grzeskowiak – 2017-04-21T06:15:53.730

6

Jelly, 6 5 4 bytes

ċ@€Ṃ

Try it online!

The first argument of the program is the set, and the second argument is the list.

Explanation

ċ@€Ṃ
ċ@   -- Create a link which finds the number of occurrences of 
          its left argument in its right argument (the list)
  €  -- Map this link over each element in the first argument
          of the program (the set)
   Ṃ -- Minimum value of this.

-1 byte thanks to @ETHproductions

-1 byte again thanks to @ETHproductions

fireflame241

Posted 2017-04-20T18:36:31.220

Reputation: 7 021

Very nice! You can save a byte by combining the links into one line: ⁹ċ$€Ṃ I have a feeling that can be made shorter by using the implicit right argument in place of ... – ETHproductions – 2017-04-20T20:25:17.150

I think ċ@€Ṃ works to save another byte... (the @ reverses the arguments to ċ) – ETHproductions – 2017-04-20T20:45:29.747

@ETHproductions Works correctly as far as I have tested. – fireflame241 – 2017-04-20T20:52:02.793

It didn't exist until May 12 of last year, but in place of @€ (with reversed arguments to the program) saves yet another byte: Try it online!

– Unrelated String – 2019-11-22T08:09:36.883

6

Jelly, 4 bytes

⁼þSṂ

Try it online!

How?

⁼þSṂ - Main link: list theSet, list theList
 þ   - outer product using the dyadic operation:
⁼    -     is equal? (non-vectorising)
  S  - sum (vectorises) (yields the number of times each element of theSet appears in theList)
   Ṃ - minimum (can only make the minimum as a multiple)

Jonathan Allan

Posted 2017-04-20T18:36:31.220

Reputation: 67 804

6

JavaScript (ES6), 56 bytes

f=(n,h)=>Math.min(...n.map(c=>h.filter($=>$==c).length))

Try it online

Alberto Rivera

Posted 2017-04-20T18:36:31.220

Reputation: 181

1Save 2 bytes by using an anonymous function and another by currying the parameters: n=>h=>Math.min(...n.map(c=>h.filter($=>$==c).length)) for 53 bytes – Shaggy – 2017-04-21T09:05:22.793

5

JavaScript (ES6), 64 bytes

(s,l)=>l.map(e=>m[s.indexOf(e)]++,m=s.map(e=>0))&&Math.min(...m)

Assumes both s and l are arrays of objects. Uses JavaScript strict equality for comparisons, so for instance [] === [] is false.

Neil

Posted 2017-04-20T18:36:31.220

Reputation: 95 035

Very interesting solution. Please return or print the result. AFAIK this returns an anonymous function. – Hubert Grzeskowiak – 2017-04-20T19:19:09.010

2@HubertGrzeskowiak The code as shown evaluates to an anonymous function. When called, the function returns the count as desired. – Neil – 2017-04-20T20:15:50.413

4

Haskell, 37 34 bytes

Thanks to @Laikoni for shaving off three bytes.

s#l=minimum[sum[1|y<-l,y==x]|x<-s]

Call with (set::[a]) # (list::[a]) where a is any type deriving Eq.

Julian Wolf

Posted 2017-04-20T18:36:31.220

Reputation: 1 139

Instead of length[y|y<-l,y==x] you can use sum[1|y<-l,y==x]. – Laikoni – 2017-04-21T00:14:06.600

@Laikoni, are you sure about that? I think I would need to use something like sum[1|y<-l,y==x,_<-y], which comes out to two bytes longer—I could definitely be missing something there, though – Julian Wolf – 2017-04-21T00:38:51.760

Never mind, you're definitely right. Good call. – Julian Wolf – 2017-04-21T00:40:27.757

3

CJam, 11 bytes

q~f{\e=}:e<

Try it online!

Explanation

q~           e# Read and eval the input
  f{\e=}     e# Map each item in the set to the number of times it appears in the list
        :e<  e# Find the minimum of the resulting list

Business Cat

Posted 2017-04-20T18:36:31.220

Reputation: 8 927

3

Mathematica, 24 bytes

Min[#/.Rule@@@Tally@#2]&

Pure function taking two lists as arguments in the suggested order and returning a nonnegative integer. Tally counts how many occurrences of every symbol occur in the input list, and #/.Rule@@@ converts each element of the input set into the corresponding number of occurrences.

Greg Martin

Posted 2017-04-20T18:36:31.220

Reputation: 13 940

3

T-SQL, 62 59 bytes

Previous version didn't work for sets with no matches

select top 1(select count(*)from l where l=s)from s order by 1

With s and l as tables and columns named the same as the table

select top 1         -- return only the first result
    (select count(*) -- count of rows
     from l          -- from table l
     where l=s)      -- for each l equal
from s               -- to each from s
order by 1           -- sort by count ascending

MickyT

Posted 2017-04-20T18:36:31.220

Reputation: 11 735

3

Swift, 39 bytes

s.map{w in l.filter{$0==w}.count}.min()

explanation:

s.map{} goes through each word in s and will produce an array of counts

w in names the mapped word for use in the next filter

l.filter{} aplies a filter to the l array

$0==w is the filter condition matching word w

.count gives the number of elements of l that met the condition

.min() returns the lowest count in the mapped result

user68380

Posted 2017-04-20T18:36:31.220

Reputation: 31

1Welcome to PPCG! I've added code formatting for your solution. You can do this by prepending 4 spaces to lines that contain code. – Mego – 2017-04-21T05:48:46.593

3

APL (Dyalog), 9 bytes

⌊/+/⎕∘.≡⎕

Try it online!

 get evaluated input (list of strings)

⎕∘.≡ get evaluated input (non-empty set of strings) and create equivalency table

+/ add across

⌊/ minimum across

Adám

Posted 2017-04-20T18:36:31.220

Reputation: 37 779

2

C++, 203 201 bytes

Thanks to @Quentin for saving two bytes!

#import<vector>
#import<string>
using T=std::vector<std::string>;
int f(T S,T L){for(int j,b,i=0;;++i)for(auto s:S){for(b=j=0;j<L.size();++j)if(L[j]==s){b=1;L.erase(begin(L)+j);break;}if(!b)return i;}}

Try it online!

Steadybox

Posted 2017-04-20T18:36:31.220

Reputation: 15 798

L.begin() -> begin(L) saves one byte :) – Quentin – 2017-04-21T09:26:01.577

Also, using T=std::vector<std::string>; saves another! Who knew modern pretty syntax could also help golfing. – Quentin – 2017-04-21T17:10:00.717

@Quentin I tried that at first. Probably there was some simple typo I didn't notice. – Steadybox – 2017-04-21T23:39:47.470

2

Perl 6,  37  18 bytes

37

{+(($_=@^a⊍@^b)≽@a)&&.values.min}

Try it

Expanded:

{
  +( # turn into a 0 if False

    (
      $_ =        # store into $_ the result of
        @^a ⊍ @^b # use the baggy multiplication operator
    ) ≽ @a        # is that the baggy superset of the set
  )

  &&          # if that is True

  .values.min # get the minimum value from the Bag in $_
}

See Sets, Bags, and Mixes for more information.


18

{@^b.Bag{@^a}.min}

Try it

Explanation:

@^b.Bag create a Bag from the values
{@^a} key into that Bag (returns a list of counts)
.min get the minimum value of the resulting list


Brad Gilbert b2gills

Posted 2017-04-20T18:36:31.220

Reputation: 12 713

Neat answers, but neither of these look like functions / complete programs – Julian Wolf – 2017-04-21T02:37:12.040

@JulianWolf I was under the impression that snippets were allowed based on the statements “Consider both inputs being defined in the current scope as s and l.” and “You don't need to define a function.” I went and edited it anyway. – Brad Gilbert b2gills – 2017-04-21T03:44:49.127

Ah, you're completely right. That must've been edited into the question after I read it. In any case, I like the aesthetic of this version even more than the last—Perl's syntax will always be a mystery to me. – Julian Wolf – 2017-04-21T03:46:50.090

@JulianWolf This isn't really a good example of Perl 6 code. I would recommend seeing Ovid's 1hr talk Perl 6 — Why People Are So Excited, or looking at the Resources tab on Perl6.org.

– Brad Gilbert b2gills – 2017-04-21T04:08:10.547

Yeah, sorry for the confusion. This is my first chllenge and I didn't know there already are rules for input and output. I changed it because most answers were using these rules even while it wasn't required. – Hubert Grzeskowiak – 2017-04-21T06:51:38.920

@HubertGrzeskowiak Those are default rules, you could have specifically stated that snippets were also allowed. (Don't do it after people have posted golfs) – Brad Gilbert b2gills – 2017-04-22T13:54:57.847

2

Axiom, 42 bytes

f(a,b)==reduce(min,[count(x,b)for x in a])

test code and results

(28) -> f(["1","2"], ["1", "2", "1", "1", "7"])
   (28)  1
                                                    Type: PositiveInteger
(29) -> f(["apple","banana"],["apple","pear","apple","banana","banana"])
   (29)  2
                                                    Type: PositiveInteger
(30) -> f(["apple","banana"],["apple","pear","apple","banana","apple"])
   (30)  1
                                                    Type: PositiveInteger
(31) -> f(["apple","banana","pear"],["apple","banana","kiwi","apple"])
   (31)  0

RosLuP

Posted 2017-04-20T18:36:31.220

Reputation: 3 036

1

PHP, 74 Bytes

<?foreach($_GET[0]as$v)$t[]=array_count_values($_GET[1])[$v];echo+min($t);

Testcases

PHP, 108 Bytes

<?[$x,$y]=$_GET;echo($a=array_intersect)($x,$y)==$x?min(($a._key)(array_count_values($y),array_flip($x))):0;

Testcases

Jörg Hülsermann

Posted 2017-04-20T18:36:31.220

Reputation: 13 026

1

C#, 36 bytes

f=(n,h)=>n.Min(c=>h.Count(x=>x==c));

n and h are string[] and the output is an int.

Try it online!

This answer is inspire by @ovs and @Alberto Rivera's logic. Thank you!

aloisdg moving to codidact.com

Posted 2017-04-20T18:36:31.220

Reputation: 1 767

1

Java, 135 bytes

int f(List<String> s,List<String> l){int n=0,i=0;while(i<s.size()){if(!l.remove(s.get(i++)))break;if(i==s.size()){n++;i=0;}};return n;}

This is my first code golf challenge and answer, so not sure about the format. Does it need to be a full compiling program? Do I need to define the parameters? Suggestions appreciated.

EDIT: wrapped code in a function. Thanks @Steadybox

Hubert Grzeskowiak

Posted 2017-04-20T18:36:31.220

Reputation: 239

An answer can be a full program, a function or some other function-like construct. You can take the parameters for example as arguments to a function or from standard input.

– Steadybox – 2017-04-21T14:19:40.437

1

Pyth, 5 bytes

hS/LF

Takes the list first and the set second. Test suite.

Explanation:

    F  Expand the input into l and s (not literally, 
                  since those are function names in Pyth, but...)
   L   for d in s:
  /        Count instances of d in l
   L   Package all the results as a list
 S     Sort the results smallest-first
h      grab the smallest element

Steven H.

Posted 2017-04-20T18:36:31.220

Reputation: 2 841

1

05AB1E, 7 bytes

v²y¢})W

Try it online!

v   }   # For each item in the first list...
 ²y¢    # Count the occurances in the second list.
     )W # Take the minimum occurrence count, return.

Magic Octopus Urn

Posted 2017-04-20T18:36:31.220

Reputation: 19 422

1

Java, 114 Bytes

<T>int a(Set<T>b,List<T>c){int m=2e32;b.stream().map(i->{int j=java.util.Collections.frequency(c,i);m=j<m?j:m;});return m;}

Tio coming soon

Explanation

  • creates local variable m.

  • maps the set to a stream.

  • for each element, if the number of occurances of the element in the list is less than m, m is set to that value.

  • returns m, which is the number of complete versions of the set

Targz

Posted 2017-04-20T18:36:31.220

Reputation: 77

0

R, 61 57 44 bytes

print(min(sapply(s,function(x)sum(l%in%x))))

Anonymous function. Apparently you don't have to define a function for this challenge. Saved 13 bytes thanks to count.

Explanation:

sum(l%in%x)) returns the number of times a string in s is found in l.

lapply(s,function(x)) applies that to each string in s separately and returns a list of sums.

min() returns the smallest from that list.

BLT

Posted 2017-04-20T18:36:31.220

Reputation: 931

Could be brought down to 40 Bytes with a for-loop: z=c();for(i in s)z[i]=sum(l%in%i);min(z) – count – 2017-04-21T09:18:16.880

Or even further to 37 bytes with sapply: min(sapply(s,function(x)sum(l%in%x))) – count – 2017-04-21T09:23:43.270

Brilliant, I always forget you can sum booleans. I'll edit that in later. I've been told I need that print() if it's not a function. – BLT – 2017-04-21T14:08:08.260

0

R 54 Bytes

f<-function(s,l) min(table(factor(l[l%in%s],levels=s)))

Explanation: creating a table of the counts of only the values in the list that also appear in the sublist.

I then turn the variable into a factor in order to generate zeros if a value that appears in the sublist does not appear in the list. Finally, I take the minimum of the counts.

Michal

Posted 2017-04-20T18:36:31.220

Reputation: 209

0

JavaScript (ES6), 59 bytes

a=>b=>a.reduce((x,y)=>(l=b.filter(s=>s==y).length)>x?x:l)|0

Try it

f=

a=>b=>a.reduce((x,y)=>(l=b.filter(s=>s==y).length)>x?x:l)|0

console.log(f(["apple","banana"])(["apple","pear","apple","banana","banana"]))
console.log(f(["apple","banana"])(["apple", "pear", "apple", "banana", "apple"]))
console.log(f(["apple","banana","pear"])(["apple","banana","kiwi","apple"]))
console.log(f(["coconut"])([]))

Shaggy

Posted 2017-04-20T18:36:31.220

Reputation: 24 623