Repository: more-itertools/more-itertools (python)

Issue:
Add a strict option to sort_together()
A *strict* option would detect data size mismatches. This would avoid silently dropping data:

```
>>> iterables = [(4, 3, 2, 1), ('a', 'b', 'c')]
>>> sort_together(iterables)
[(2, 3, 4), ('c', 'b', 'a')]
```

Pull request description:
Add option `strict` to `sort_together`
### Issue reference
<!-- If you're adding a new feature, please make an issue first -->
<!-- If you're fixing a trivial bug (e.g. a typo) you need not make an issue first -->
<!-- If you're fixing a non-trivial bug, please go ahead and make an issue first -->
<!-- Not all proposals for new functionality will be accepted, so please save yourself some work by checking first with an issue -->
Closes #890 

### Changes
<!-- Describe what your PR adds, fixes, or changes here -->
Add option `strict` to detect the mismatch dimension of iterables.

### Checks and tests
<!-- Please run `make all-checks` to help make sure your branch meets the standards enforced by GitHub Actions. -->
Done.

Patch:
diff --git a/more_itertools/more.py b/more_itertools/more.py
index 7fa96ad..1d4a090 100755
--- a/more_itertools/more.py
+++ b/more_itertools/more.py
@@ -1792,7 +1792,9 @@ def zip_offset(*iterables, offsets, longest=False, fillvalue=None):
     return zip(*staggered)
 
 
-def sort_together(iterables, key_list=(0,), key=None, reverse=False):
+def sort_together(
+    iterables, key_list=(0,), key=None, reverse=False, strict=False
+):
     """Return the input iterables sorted together, with *key_list* as the
     priority for sorting. All iterables are trimmed to the length of the
     shortest one.
@@ -1831,6 +1833,10 @@ def sort_together(iterables, key_list=(0,), key=None, reverse=False):
         >>> sort_together([(1, 2, 3), ('c', 'b', 'a')], reverse=True)
         [(3, 2, 1), ('a', 'b', 'c')]
 
+    If the *strict* keyword argument is ``True``, then
+    ``UnequalIterablesError`` will be raised if any of the iterables have
+    different lengths.
+
     """
     if key is None:
         # if there is no key function, the key argument to sorted is an
@@ -1853,8 +1859,9 @@ def sort_together(iterables, key_list=(0,), key=None, reverse=False):
                 *get_key_items(zipped_items)
             )
 
+    zipper = zip_equal if strict else zip
     return list(
-        zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse))
+        zipper(*sorted(zipper(*iterables), key=key_argument, reverse=reverse))
     )
 
 
diff --git a/more_itertools/more.pyi b/more_itertools/more.pyi
index ef82f39..f1a155d 100644
--- a/more_itertools/more.pyi
+++ b/more_itertools/more.pyi
@@ -321,6 +321,7 @@ def sort_together(
     key_list: Iterable[int] = ...,
     key: Callable[..., Any] | None = ...,
     reverse: bool = ...,
+    strict: bool = ...,
 ) -> list[tuple[_T, ...]]: ...
 def unzip(iterable: Iterable[Sequence[_T]]) -> tuple[Iterator[_T], ...]: ...
 def divide(n: int, iterable: Iterable[_T]) -> list[Iterator[_T]]: ...


Test patch:
diff --git a/tests/test_more.py b/tests/test_more.py
index 89317cc..b25343f 100644
--- a/tests/test_more.py
+++ b/tests/test_more.py
@@ -2173,6 +2173,29 @@ class SortTogetherTest(TestCase):
             ],
         )
 
+    def test_strict(self):
+        # Test for list of lists or tuples
+        self.assertRaises(
+            mi.UnequalIterablesError,
+            lambda: mi.sort_together(
+                [(4, 3, 2, 1), ('a', 'b', 'c')], strict=True
+            ),
+        )
+
+        # Test for list of iterables
+        self.assertRaises(
+            mi.UnequalIterablesError,
+            lambda: mi.sort_together([range(4), range(5)], strict=True),
+        )
+
+        # Test for iterable of iterables
+        self.assertRaises(
+            mi.UnequalIterablesError,
+            lambda: mi.sort_together(
+                (range(i) for i in range(4)), strict=True
+            ),
+        )
+
 
 class DivideTest(TestCase):
     """Tests for divide()"""