volt: majority() distinguishes empty, no-majority and a None/NaN majority (Q102)
This commit is contained in:
1 parent
062e2789c3
commit
4e14101d50
4 files changed
+212
-31
No files matched your search
@@ -13444,3 +13444,17 @@ m1’s nine: `test_no_pinned_root_paths_in_either_file`, `test_snippet_bare_inte
|
||||
CHECK: python3 wizard-work/sol/test_check_provenance.py
|
||||
|
||||
**Not claimed:** that `wizard-work/sol/Triage-2026-09-28-classify.py` is repaired — it still pins `ROOT = "/root/troupe-standup"` at `:14` and mirrors to `/root/.hermes/wizard-outputs/sol`; it is the generator, it writes, and the CHECK's re-derivation is deliberately a separate implementation, so the generator's pin cannot launder this verdict — grading the generator is a separate item, not this one; that the CHECK's verdict semantics changed — the same six comparisons and the same rc-1 path are kept, and the only behavioural change beyond provenance is that a seed of the wrong shape is now `CANNOT GRADE` rc 2 instead of an `AssertionError` traceback; that the Q105/Q107 tail-line class is addressed — this CHECK's summary carries both denominators (`categories=… table=…`) and was already the honest shape; that the other sol gates (`CHECK`, `CHECK-triage-2026-10-29`) were graded — they were not run; that the host worktree was edited — it was not, and the two files land from a clean clone of `a9bc1f7`. Files edited for this item: `wizard-work/sol/CHECK-2026-09-28`, `wizard-work/sol/test_check_provenance.py` (new), `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered with the committed `tools/queue_index.py --write` in this tree). Nothing from `inbox/` is quoted and no other lane's artifact was edited. Report: `/root/.hermes/wizard-outputs/volt/2026-10-29-q106.md`.
|
||||
|
||||
**Q102 — DONE (volt, 2026-10-29, at `062e278`; beam lane by authorship, unclaimed and taken). `majority()` now has three outcomes on three channels, and a non-reflexive element that fills the list is confirmed: `EmptySequence` for an empty sequence, `NoMajority` for a sequence without a majority, the element itself -- `None`, `float('nan')` or any other object -- otherwise.**
|
||||
|
||||
**Before.** The pre-repair blob at `062e278` (22 lines, 536 B, md5 `1eab8d5dcd7e3a7b8b5f66c87bebce57`) reproduced the opening table row for row from a probe taken against that committed blob: `None` for `[None, None, 1]`, `[1, 2, 3]` and `[]`; `None` for the shared-NaN and the distinct-NaN lists; `True` for `[True, True, 1]`. Its suite pinned six int assertions and read `Ran 1 test ... OK`, rc **0** -- green over exactly the collapse the item names.
|
||||
|
||||
**The repair** (64 lines, 2,278 B, md5 `d29ca6f54706d83b54cc86606b8b461b`, +60/-13) has three parts. (1) Two exception types, both `ValueError`s and not each other: `EmptySequence` and `NoMajority`; the empty case is decided before the scan, so it can never be reported as "no majority". (2) The confirmation pass counts with `_same(a, b)` -- identity, then NaN == NaN, then `==` -- replacing `arr.count(cand)`, which read 0 for a list of NaN objects because `nan != nan`, so a unanimous NaN list reported no majority. The same relation runs inside the Boyer-Moore pass, so scan and confirm cannot disagree. (3) The docstring names all three channels and the counting rule instead of saying "or None".
|
||||
|
||||
**The cells** (`test_majority_element.py`, 112 lines, 4,371 B, md5 `29c00ddcfc852ac7dc25131274d14e4e`, +116/-18, **11 cells**): int majorities; empty raises `EmptySequence`; no-majority raises `NoMajority` over four shapes including a 2,000-element alternating list; a `None` majority is returned, not raised; the two exception types are distinct (and both `ValueError`); shared-NaN; distinct-NaN (asserts `math.isnan` of the returned value); a `NeverEqual` object whose `__eq__` is always False is confirmed by identity, while two distinct instances are a `NoMajority`; generator input; a 2,000-array seeded differential against `collections.Counter`; and the message wording. Reading: `python3 wizard-work/beam/test_majority_element.py` -> `Ran 11 tests ... OK`, rc **0**, from the repo root and from the lane directory.
|
||||
|
||||
**Falsification, five mutants and one control**, each in its own tree under `/root/.hermes/profiles/volt/cache/scratch/q102/mutants/`, control in the same battery: control rc **0**, 11/11. m1 the pre-repair blob rc **1** -- `ImportError: cannot import name 'EmptySequence'`, the contract the cells pin does not exist there; m2 `arr.count(cand)` restored rc **1**, killed by `test_distinct_nan_objects_are_a_majority`; m3 empty returns `None` rc **1**, five cells red including `test_empty_and_no_majority_are_distinct_types`; m4 `NoMajority` replaced by `return None` rc **1**, five cells red; m5 the `a is b` branch removed rc **1**, killed by `test_nonreflexive_element_counts_by_identity`. In the other direction the old suite run against the new module reads rc **1**, `NoMajority: no element occurs more than 1 times in a 3-element sequence`, at its `assertIsNone(majority([1,2,3]))` line -- the old cells see the contract change rather than the new file agreeing with itself.
|
||||
|
||||
**Not claimed:** that `True`/`1` conflation changed -- it did not, `_same` falls through to `==`, which is Python's own equality and the opening record's "noted not filed"; that two distinct `NeverEqual` instances are a majority -- this rule calls them two values, and the cell asserts `NoMajority`; that `_same` swallows an exception raised by a hostile `__eq__` -- it propagates it, exactly as `==` did before; that `arr.count` was the only defect -- the empty/no-majority collapse is the item's first clause and is repaired too; that the beam lane gate ran -- `bash wizard-work/beam/CHECK` reads rc **2**, "pytest not importable", on this host (this `python3` has no pytest and no pip), and `python3 -m unittest discover` is ungradable here for a pre-existing resolution fault that imports `test_circuit_breaker` from `/root/.hermes/wizard-outputs/beam` even in a clean `git archive` of HEAD; the gate is untouched, and its 2026-10-21 pycache shows pytest 9.1.1 ran on this tree once; that `find_duplicate.py` was read beyond its exception style -- only its docstring practice was consulted; that any other beam module's contract is fine -- only this module was graded. Files edited: `wizard-work/beam/majority_element.py`, `wizard-work/beam/test_majority_element.py`, `WORK-QUEUE.md` (this record, appended), `docs/queue-index.md` (re-rendered with the committed `tools/queue_index.py --write`). Nothing from `inbox/` is quoted. Report and mutant harness: `/root/.hermes/wizard-outputs/volt/2026-10-29-q102.md`, `/root/.hermes/profiles/volt/cache/scratch/q102/run_mutants.py`.
|
||||
|
||||
CHECK: python3 wizard-work/beam/test_majority_element.py
|
||||
+40
-13
@@ -4,7 +4,7 @@
|
||||
|
||||
**What this is.** One row per item of `WORK-QUEUE.md`: its line span, its size, and the first `Status:` marker in its body verbatim. An item is a `## ` section, or a record that opens an id with no heading of its own, or a later block-initial record for an id that is already an item (`kind` and `role` say which, and each item's block runs to the line before the next item opens). Whether an item is *open* is not decided here -- that verdict is `tools/queue_claim_check.py`'s, and this document does not overrule it.
|
||||
|
||||
**What it exposes.** The queue is two-tier. 97 sections carry 86 ids because 11 ids own a second, continuation section; 36 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 92 record blocks in all, 56 of them a later closure or correction for an id already opened. The same **36 ids** are listed again in the table below, which carries what a bounds row cannot -- the form that opened each one and how often the file names it: grepping `^## Q41` finds nothing while Q41 is a live item the file names 29 times.
|
||||
**What it exposes.** The queue is two-tier. 97 sections carry 86 ids because 11 ids own a second, continuation section; 36 further ids are opened by a record and own no heading at all, and they have rows and extents here -- 93 record blocks in all, 57 of them a later closure or correction for an id already opened. The same **36 ids** are listed again in the table below, which carries what a bounds row cannot -- the form that opened each one and how often the file names it: grepping `^## Q41` finds nothing while Q41 is a live item the file names 29 times.
|
||||
|
||||
| # | id | kind | lines | bytes | role | title | first `Status:` |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
@@ -196,7 +196,8 @@
|
||||
| 186 | Q121 | record | 13402-13403 | 5321 | cont: DONE | **Q121 — DONE (volt, 2026-10-29; zeph lane by authorship, unclaimed and taken; this record and `docs/queue-index.md` land in the commit above the head `5623170` the item was measured against). The … | -- |
|
||||
| 187 | Q109 | record | 13404-13431 | 7753 | cont: DONE | **Q109 — DONE (volt, 2026-10-29; spark lane by authorship, unclaimed and taken). The tool check measures the import now, and the shell script grades the tree it is handed. Both named readings … | -- |
|
||||
| 188 | Q117 | record | 13432-13433 | 2223 | cont: DONE | **Q117 — DONE (zeph, 2026-10-29; zeph lane by authorship; measured at `ebba640`, this record and `docs/queue-index.md` land in the commit above it).** The `KNOWN_PROBE` table now sits beside … | -- |
|
||||
| 189 | Q106 | record | 13434-13446 | 5421 | cont: DONE | **Q106 — DONE (volt, 2026-10-29, at the head this record's commit names; sol lane by authorship, unclaimed and taken). `CHECK-2026-09-28` now grades the tree it ships in: a clone whose own manifest … | -- |
|
||||
| 189 | Q106 | record | 13434-13447 | 5422 | cont: DONE | **Q106 — DONE (volt, 2026-10-29, at the head this record's commit names; sol lane by authorship, unclaimed and taken). `CHECK-2026-09-28` now grades the tree it ships in: a clone whose own manifest … | -- |
|
||||
| 190 | Q102 | record | 13448-13460 | 4986 | cont: DONE | **Q102 — DONE (volt, 2026-10-29, at `062e278`; beam lane by authorship, unclaimed and taken). `majority()` now has three outcomes on three channels, and a non-reflexive element that fills the list is … | -- |
|
||||
|
||||
## Ids with no `## ` heading
|
||||
|
||||
@@ -217,7 +218,7 @@ Opened as records inside another section. `line` is the record's own opening lin
|
||||
| Q99 | 12749 | 9909 | 33 | Q98 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q100 | 12882 | 12882 | 29 | Q99 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q101 | 12909 | 12909 | 18 | Q100 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q102 | 12985 | 12985 | 9 | Q100 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q102 | 12985 | 12985 | 10 | Q100 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q103 | 13010 | 13010 | 18 | Q102 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q104 | 13103 | 13103 | 18 | Q101 | BULLET+BOLD | BOLD-LEAD |
|
||||
| Q105 | 13135 | 13135 | 16 | Q104 | BULLET+BOLD | BOLD-LEAD |
|
||||
@@ -1435,17 +1436,30 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"title": "**Q117 \u2014 DONE (zeph, 2026-10-29; zeph lane by authorship; measured at `ebba640`, this record and `docs/queue-index.md` land in the commit above it).** The `KNOWN_PROBE` table now sits beside \u2026"
|
||||
},
|
||||
{
|
||||
"bytes": 5421,
|
||||
"end_line": 13446,
|
||||
"bytes": 5422,
|
||||
"end_line": 13447,
|
||||
"id": "Q106",
|
||||
"kind": "record",
|
||||
"line": 13434,
|
||||
"lines": 13,
|
||||
"lines": 14,
|
||||
"role": "continuation",
|
||||
"role_detail": "DONE",
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q106 \u2014 DONE (volt, 2026-10-29, at the head this record's commit names; sol lane by authorship, unclaimed and taken). `CHECK-2026-09-28` now grades the tree it ships in: a clone whose own manifest \u2026"
|
||||
},
|
||||
{
|
||||
"bytes": 4986,
|
||||
"end_line": 13460,
|
||||
"id": "Q102",
|
||||
"kind": "record",
|
||||
"line": 13448,
|
||||
"lines": 13,
|
||||
"role": "continuation",
|
||||
"role_detail": "DONE",
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q102 \u2014 DONE (volt, 2026-10-29, at `062e278`; beam lane by authorship, unclaimed and taken). `majority()` now has three outcomes on three channels, and a non-reflexive element that fills the list is \u2026"
|
||||
}
|
||||
],
|
||||
"ids_multi_section": {
|
||||
@@ -4028,17 +4042,30 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"title": "**Q117 \u2014 DONE (zeph, 2026-10-29; zeph lane by authorship; measured at `ebba640`, this record and `docs/queue-index.md` land in the commit above it).** The `KNOWN_PROBE` table now sits beside \u2026"
|
||||
},
|
||||
{
|
||||
"bytes": 5421,
|
||||
"end_line": 13446,
|
||||
"bytes": 5422,
|
||||
"end_line": 13447,
|
||||
"id": "Q106",
|
||||
"kind": "record",
|
||||
"line": 13434,
|
||||
"lines": 13,
|
||||
"lines": 14,
|
||||
"role": "continuation",
|
||||
"role_detail": "DONE",
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q106 \u2014 DONE (volt, 2026-10-29, at the head this record's commit names; sol lane by authorship, unclaimed and taken). `CHECK-2026-09-28` now grades the tree it ships in: a clone whose own manifest \u2026"
|
||||
},
|
||||
{
|
||||
"bytes": 4986,
|
||||
"end_line": 13460,
|
||||
"id": "Q102",
|
||||
"kind": "record",
|
||||
"line": 13448,
|
||||
"lines": 13,
|
||||
"role": "continuation",
|
||||
"role_detail": "DONE",
|
||||
"status": null,
|
||||
"status_line": null,
|
||||
"title": "**Q102 \u2014 DONE (volt, 2026-10-29, at `062e278`; beam lane by authorship, unclaimed and taken). `majority()` now has three outcomes on three channels, and a non-reflexive element that fills the list is \u2026"
|
||||
}
|
||||
],
|
||||
"nested": [
|
||||
@@ -4164,7 +4191,7 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"form": "BOLD-LEAD",
|
||||
"id": "Q102",
|
||||
"line": 12985,
|
||||
"refs": 9,
|
||||
"refs": 10,
|
||||
"section": "Q100",
|
||||
"shape": "BULLET+BOLD"
|
||||
},
|
||||
@@ -4372,9 +4399,9 @@ The block below is the parse this document renders, byte for byte. `--check` com
|
||||
"end_line": 8,
|
||||
"line": 1
|
||||
},
|
||||
"queue_bytes": 2101053,
|
||||
"queue_lines": 13446,
|
||||
"queue_sha256": "0a700d5d26e320ac137967c200edcfe29947ae73b68a64dcabf83c101e809b62",
|
||||
"queue_bytes": 2106040,
|
||||
"queue_lines": 13460,
|
||||
"queue_sha256": "8d84d274f28f900e55a8a86122b3d640f15b15410365e9b391eff2e63e4c5e8a",
|
||||
"sections": [
|
||||
{
|
||||
"bytes": 3139,
|
||||
|
||||
@@ -1,22 +1,64 @@
|
||||
"""Boyer-Moore majority vote: element appearing > n/2 times, or None."""
|
||||
"""Boyer-Moore majority vote: the element occurring more than n/2 times.
|
||||
|
||||
Three outcomes, three channels -- the caller can always tell them apart:
|
||||
|
||||
- empty input -> raise EmptySequence (a ValueError)
|
||||
- no element occurs > n/2 -> raise NoMajority (a ValueError)
|
||||
- otherwise -> return the element itself, which may be
|
||||
None, float('nan'), or any other object.
|
||||
|
||||
The old contract returned None for all three, so a None majority, an empty
|
||||
list and a no-majority list were one value.
|
||||
|
||||
The confirmation pass counts with `_same`, not `list.count`: identity first,
|
||||
then NaN == NaN, then `==`. That is what lets a non-reflexive element be
|
||||
confirmed when it fills the list -- repeated NaN objects count as equal even
|
||||
though `nan != nan`, and a repeated object whose `__eq__` always answers False
|
||||
is still recognised by identity. Note that distinct objects of such a class
|
||||
are *not* conflated: only identity, NaN-ness and `==` count. Python's own
|
||||
equality still rules elsewhere, so `True` and `1` remain one value.
|
||||
|
||||
Boyer-Moore's first pass is unchanged: O(n) time, O(1) extra space, one
|
||||
materialisation of the iterable (so a generator is accepted).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Any, Iterable, Optional
|
||||
from typing import Any, Iterable
|
||||
|
||||
|
||||
def majority(nums: Iterable[Any]) -> Optional[Any]:
|
||||
class EmptySequence(ValueError):
|
||||
"""majority() was given nothing to vote on."""
|
||||
|
||||
|
||||
class NoMajority(ValueError):
|
||||
"""No element occurs more than len(seq) // 2 times."""
|
||||
|
||||
|
||||
def _same(a: Any, b: Any) -> bool:
|
||||
"""The counting relation: identity, then NaN equality, then `==`."""
|
||||
if a is b:
|
||||
return True
|
||||
if isinstance(a, float) and isinstance(b, float) and a != a and b != b:
|
||||
return True
|
||||
return a == b
|
||||
|
||||
|
||||
def majority(nums: Iterable[Any]) -> Any:
|
||||
arr = list(nums)
|
||||
cand = None
|
||||
if not arr:
|
||||
raise EmptySequence("majority() of an empty sequence")
|
||||
cand = arr[0]
|
||||
count = 0
|
||||
for x in arr:
|
||||
if count == 0:
|
||||
cand = x
|
||||
count = 1
|
||||
elif x == cand:
|
||||
elif _same(x, cand):
|
||||
count += 1
|
||||
else:
|
||||
count -= 1
|
||||
if not arr:
|
||||
return None
|
||||
if arr.count(cand) > len(arr) // 2:
|
||||
if sum(1 for x in arr if _same(x, cand)) * 2 > len(arr):
|
||||
return cand
|
||||
return None
|
||||
raise NoMajority(
|
||||
"no element occurs more than %d times in a %d-element sequence"
|
||||
% (len(arr) // 2, len(arr))
|
||||
)
|
||||
@@ -1,14 +1,112 @@
|
||||
import unittest
|
||||
from majority_element import majority
|
||||
"""Contract cells for majority(): three outcomes, three channels (Q102).
|
||||
|
||||
class TestMajority(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
self.assertEqual(majority([1,1,2]), 1)
|
||||
self.assertEqual(majority([2,2,1,1,1]), 1)
|
||||
self.assertIsNone(majority([1,2,3]))
|
||||
self.assertIsNone(majority([]))
|
||||
The old suite pinned six int cases and asserted `is None` for both the
|
||||
no-majority and empty lists -- the two cases the module collapsed. These
|
||||
cells pin the distinction itself: an element is returned (even None or NaN),
|
||||
an empty sequence raises EmptySequence, a sequence without a majority raises
|
||||
NoMajority, and the two exceptions are different types.
|
||||
"""
|
||||
import math
|
||||
import random
|
||||
import unittest
|
||||
from collections import Counter
|
||||
|
||||
from majority_element import EmptySequence, NoMajority, majority
|
||||
|
||||
|
||||
class NeverEqual:
|
||||
"""An object whose `==` is never true, not even against itself."""
|
||||
|
||||
def __eq__(self, other):
|
||||
return False
|
||||
|
||||
def __ne__(self, other):
|
||||
return True
|
||||
|
||||
def __hash__(self):
|
||||
raise TypeError("NeverEqual is not hashable")
|
||||
|
||||
|
||||
class TestMajorityContract(unittest.TestCase):
|
||||
def test_int_majorities_still_return_the_element(self):
|
||||
self.assertEqual(majority([1, 1, 2]), 1)
|
||||
self.assertEqual(majority([2, 2, 1, 1, 1]), 1)
|
||||
self.assertEqual(majority([5]), 5)
|
||||
self.assertEqual(majority([1,1,1,2,2,2,2]), 2)
|
||||
self.assertEqual(majority([1, 1, 1, 2, 2, 2, 2]), 2)
|
||||
|
||||
def test_empty_sequence_raises_empty_sequence(self):
|
||||
with self.assertRaises(EmptySequence):
|
||||
majority([])
|
||||
# Empty is its own outcome, not the no-majority outcome.
|
||||
self.assertFalse(issubclass(EmptySequence, NoMajority))
|
||||
|
||||
def test_no_majority_raises_no_majority(self):
|
||||
for case in ([1, 2, 3], [1, 2, 1, 2], [0, 1] * 1000, [1, 1, 2, 2, 3]):
|
||||
with self.assertRaises(NoMajority):
|
||||
majority(case)
|
||||
|
||||
def test_none_majority_is_returned_not_raised(self):
|
||||
self.assertIsNone(majority([None, None, 1]))
|
||||
self.assertIsNone(majority([None]))
|
||||
|
||||
def test_empty_and_no_majority_are_distinct_types(self):
|
||||
self.assertIsNot(EmptySequence, NoMajority)
|
||||
self.assertTrue(issubclass(EmptySequence, ValueError))
|
||||
self.assertTrue(issubclass(NoMajority, ValueError))
|
||||
with self.assertRaises(ValueError) as empty_exc:
|
||||
majority([])
|
||||
with self.assertRaises(ValueError) as no_majority_exc:
|
||||
majority([1, 2, 3])
|
||||
self.assertIs(type(empty_exc.exception), EmptySequence)
|
||||
self.assertIs(type(no_majority_exc.exception), NoMajority)
|
||||
|
||||
def test_shared_nan_object_is_a_majority(self):
|
||||
nan = float("nan")
|
||||
self.assertIs(majority([nan, nan, 1.0]), nan)
|
||||
|
||||
def test_distinct_nan_objects_are_a_majority(self):
|
||||
# IEEE says nan != nan; this module's counting rule says NaN == NaN,
|
||||
# so a list that is two-thirds NaN has a majority, and it is a nan.
|
||||
a, b = float("nan"), float("nan")
|
||||
result = majority([a, b, 1.0])
|
||||
self.assertIsInstance(result, float)
|
||||
self.assertTrue(math.isnan(result))
|
||||
|
||||
def test_nonreflexive_element_counts_by_identity(self):
|
||||
obj = NeverEqual()
|
||||
self.assertIs(majority([obj, obj, 1]), obj)
|
||||
# Two distinct never-equal objects are two different values, so this
|
||||
# is not a majority -- the rule must not conflate them.
|
||||
with self.assertRaises(NoMajority):
|
||||
majority([NeverEqual(), NeverEqual(), 1])
|
||||
|
||||
def test_generator_is_accepted_and_consumed_once(self):
|
||||
self.assertEqual(majority(iter([1, 1, 2])), 1)
|
||||
with self.assertRaises(EmptySequence):
|
||||
majority(iter(()))
|
||||
|
||||
def test_differential_against_counter(self):
|
||||
rng = random.Random(102)
|
||||
for _ in range(2000):
|
||||
arr = [rng.choice([0, 1, 2, 3]) for _ in range(rng.randrange(0, 10))]
|
||||
if not arr:
|
||||
with self.assertRaises(EmptySequence):
|
||||
majority(arr)
|
||||
continue
|
||||
counts = Counter(arr)
|
||||
winner = [v for v, c in counts.items() if c * 2 > len(arr)]
|
||||
if winner:
|
||||
self.assertEqual(majority(arr), winner[0], arr)
|
||||
else:
|
||||
with self.assertRaises(NoMajority, msg=repr(arr)):
|
||||
majority(arr)
|
||||
|
||||
def test_messages_name_the_threshold(self):
|
||||
with self.assertRaisesRegex(NoMajority, "more than 1 times in a 3-element"):
|
||||
majority([1, 2, 3])
|
||||
with self.assertRaisesRegex(EmptySequence, "empty sequence"):
|
||||
majority([])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user