Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lacking a dirty way to count elements #77

Open
flaeppe opened this issue Sep 7, 2023 · 6 comments
Open

Lacking a dirty way to count elements #77

flaeppe opened this issue Sep 7, 2023 · 6 comments

Comments

@flaeppe
Copy link

flaeppe commented Sep 7, 2023

I wonder if there's a dirty equals way to assert on element count?

I suppose it's possible to use IsListOrTuple with check_order=False. But then it's the precondition of having a list/tuple and explicitly multiply each element.

e.g.

from dirty_equals import IsListOrTuple
[3, 2, 1, 3, 2, 1] == IsListOrTuple(1, 1, 2, 2, 3, 3, check_order=False)

Another one is Contains, but as far as I can see it can't be upper bounded on "how many of something"?


Could this be some extension of Contains? e.g. under a parameter counts={<elem>: <count>}.

from dirty_equals import Contains
[3, 2, 1, 3, 2, 1] == Contains(counts={1: 2, 2: 2, 3: 2})

I suppose this might also imply some sort of partial={True|False} argument for Contains, for convenience?

Additionally, <element> of counts in a case like above could probably be useful as dirty equals types? e.g.

[("a", 1), ("b", 2), ("a", 1)] == Contains(counts={IsTuple(IsStr(), 1): 2, IsTuple(IsStr(), 2): 1})
@alexmojaki
Copy link
Contributor

Why not use collections.Counter?

@flaeppe
Copy link
Author

flaeppe commented Sep 7, 2023

Yes, of course. That's not a dirty approach though and then what about the left hand side?

What if it wraps some sort of "EqualCounter"? So it counts items using equality instead of identity. Could that help align with other dirty types?

@alexmojaki
Copy link
Contributor

assert Counter([3, 2, 1, 3, 2, 1]) == {1: 2, 2: 2, 3: 2}

Assuming the left side was something more complicated and you wanted to only do transformations on the right, maybe combined with other dirty operators:

assert [3, 2, 1, 3, 2, 1] == IsListOrTuple(*Counter({1: 2, 2: 2, 3: 2}).elements(), check_order=False)

That way you don't have to "explicitly multiply each element".

But then it's the precondition of having a list/tuple

IsIterable and IsSequence sound like sensible things to have.

@flaeppe
Copy link
Author

flaeppe commented Sep 8, 2023

What if I have something non-hashable on the left hand side that I want to count?

assert [{"a": 1}, {"b": 2}, {"a": 1}, {"c": 3}, {"a": 1}] == IsListOrTuple(???)

If I have my EqualCounter I could perhaps do

assert [{"a": 1}, {"b": 2}, {"a": 1}, {"c": 3}, {"a": 1}] == EqualCounter((IsDict(a=1), 2), (IsDict(b=2), 1), (IsDict(c=3), 1))

As the "EqualCounter" in this case would compare with each expected item with ==. Additionally one would probably have to figure out a decent way on how to handle items being equal to multiple other items, I suppose a naive approach is to only count each item once and towards the first encountered equal element.

@samuelcolvin
Copy link
Owner

It might be easiest to add your own custom type?

@flaeppe
Copy link
Author

flaeppe commented Sep 8, 2023

Yeah, sure, I'll try that out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants