Skip to content

Commit be6de5b

Browse files
authored
Merge pull request #225 from data-8/fewerlists
Reduce use of lists
2 parents d5ccaf6 + b0e92c7 commit be6de5b

File tree

4 files changed

+110
-11
lines changed

4 files changed

+110
-11
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
77
## [Unreleased]
88
None yet.
99

10+
## v0.6.0
11+
### Changed
12+
- Added `make_array` to make arrays without lists. (#224)
13+
- `Table.select`, `drop`, and `with_columns` now accept variable arguments in addition to lists. (#224)
14+
1015
## v0.5.3
1116
### Changed
1217
- Allow charting methods to select particular columns and default to

datascience/tables.py

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,15 @@ def copy(self, *, shallow=False):
527527
self._add_column_and_format(table, label, column)
528528
return table
529529

530-
def select(self, column_label_or_labels):
530+
def select(self, *column_label_or_labels):
531531
"""Return a Table with selected column or columns by label or index.
532532
533533
Args:
534-
``column_label_or_labels`` (string or list of strings): The header
535-
names or indices of the columns to be selected. ``column_label_or_labels`` must
536-
be an existing header name, or a valid column index.
534+
``column_label_or_labels`` (string, list of strings, or several
535+
separate argument strings): The header names or indices of the
536+
columns to be selected. ``column_label_or_labels`` must
537+
be an existing header name, or a valid column index, or a list
538+
thereof.
537539
538540
Returns:
539541
An instance of ``Table`` containing only selected columns.
@@ -557,6 +559,11 @@ def select(self, column_label_or_labels):
557559
6
558560
5
559561
5
562+
>>> t.select('burgers', 'calories')
563+
burgers | calories
564+
cheeseburger | 743
565+
hamburger | 651
566+
veggie burger | 582
560567
>>> t.select(1)
561568
prices
562569
6
@@ -567,8 +574,13 @@ def select(self, column_label_or_labels):
567574
743 | cheeseburger
568575
651 | hamburger
569576
582 | veggie burger
577+
>>> t.select(2, 0)
578+
calories | burgers
579+
743 | cheeseburger
580+
651 | hamburger
581+
582 | veggie burger
570582
"""
571-
labels = self._as_labels(column_label_or_labels)
583+
labels = self._varargs_as_labels(column_label_or_labels)
572584
table = Table()
573585
for label in labels:
574586
self._add_column_and_format(table, label, np.copy(self[label]))
@@ -583,7 +595,7 @@ def take(self):
583595
def exclude(self):
584596
raise NotImplementedError()
585597

586-
def drop(self, column_label_or_labels):
598+
def drop(self, *column_label_or_labels):
587599
"""Return a Table with only columns other than selected label or labels.
588600
589601
Args:
@@ -613,18 +625,28 @@ def drop(self, column_label_or_labels):
613625
6
614626
5
615627
5
628+
>>> t.drop('burgers', 'calories')
629+
prices
630+
6
631+
5
632+
5
616633
>>> t.drop([0, 2])
617634
prices
618635
6
619636
5
620637
5
638+
>>> t.drop(0, 2)
639+
prices
640+
6
641+
5
642+
5
621643
>>> t.drop(1)
622644
burgers | calories
623645
cheeseburger | 743
624646
hamburger | 651
625647
veggie burger | 582
626648
"""
627-
exclude = _as_labels(column_label_or_labels)
649+
exclude = _varargs_labels_as_list(column_label_or_labels)
628650
return self.select([c for (i, c) in enumerate(self.labels) if i not in exclude and c not in exclude])
629651

630652
def where(self, column_or_label, value_or_predicate=None, other=None):
@@ -1068,6 +1090,11 @@ def _as_labels(self, label_or_labels):
10681090
"""Convert single label to list and convert indices to labels."""
10691091
return [self._as_label(s) for s in _as_labels(label_or_labels)]
10701092

1093+
def _varargs_as_labels(self, label_list):
1094+
"""Converts a list of labels or singleton list of list of labels into
1095+
a list of labels. Useful when labels are passed as varargs."""
1096+
return self._as_labels(_varargs_labels_as_list(label_list))
1097+
10711098
def _unused_label(self, label):
10721099
"""Generate an unused label."""
10731100
original = label
@@ -1327,7 +1354,7 @@ def with_column(self, label, values):
13271354
new_table.append_column(label, values)
13281355
return new_table
13291356

1330-
def with_columns(self, labels_and_values):
1357+
def with_columns(self, *labels_and_values):
13311358
"""Return a table with additional or replaced columns.
13321359
13331360
Args:
@@ -1341,18 +1368,52 @@ def with_columns(self, labels_and_values):
13411368
letter | count
13421369
c | 2
13431370
d | 4
1371+
>>> Table().with_columns(
1372+
... 'letter', ['c', 'd'],
1373+
... 'count', [2, 4],
1374+
... )
1375+
letter | count
1376+
c | 2
1377+
d | 4
13441378
>>> Table().with_columns([
13451379
... ['letter', ['c', 'd']],
13461380
... ['count', [2, 4]],
13471381
... ])
13481382
letter | count
13491383
c | 2
13501384
d | 4
1385+
>>> Table().with_columns(
1386+
... ['letter', ['c', 'd']],
1387+
... ['count', [2, 4]],
1388+
... )
1389+
letter | count
1390+
c | 2
1391+
d | 4
1392+
>>> Table().with_columns([
1393+
... ['letter', ['c', 'd']],
1394+
... ])
1395+
letter
1396+
c
1397+
d
1398+
>>> Table().with_columns(
1399+
... 'letter', ['c', 'd'],
1400+
... )
1401+
letter
1402+
c
1403+
d
1404+
>>> Table().with_columns(
1405+
... ['letter', ['c', 'd']],
1406+
... )
1407+
letter
1408+
c
1409+
d
13511410
>>> Table().with_columns({'letter': ['c', 'd']})
13521411
letter
13531412
c
13541413
d
13551414
"""
1415+
if len(labels_and_values) == 1:
1416+
labels_and_values = labels_and_values[0]
13561417
if isinstance(labels_and_values, collections.abc.Mapping):
13571418
labels_and_values = list(labels_and_values.items())
13581419
if not isinstance(labels_and_values, collections.abc.Sequence):
@@ -2176,6 +2237,20 @@ def _as_labels(column_label_or_labels):
21762237
else:
21772238
return column_label_or_labels
21782239

2240+
def _varargs_labels_as_list(label_list):
2241+
"""Return a list of labels for a list of labels or singleton list of list
2242+
of labels."""
2243+
if len(label_list) == 0:
2244+
return []
2245+
elif not _is_non_string_iterable(label_list[0]):
2246+
# Assume everything is a label. If not, it'll be caught later.
2247+
return label_list
2248+
elif len(label_list) == 1:
2249+
return label_list[0]
2250+
else:
2251+
raise ValueError("Labels {} contain more than list.".format(label_list),
2252+
"Pass just one list of labels.")
2253+
21792254
def _assert_same(values):
21802255
"""Assert that all values are identical and return the unique value."""
21812256
assert len(values) > 0

datascience/util.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Utility functions"""
22

3-
__all__ = ['percentile', 'plot_cdf_area', 'plot_normal_cdf', 'table_apply',
4-
'minimize']
3+
__all__ = ['make_array', 'percentile', 'plot_cdf_area', 'plot_normal_cdf',
4+
'table_apply', 'minimize']
55

66
import numpy as np
77
import pandas as pd
@@ -14,6 +14,25 @@
1414
import math
1515

1616

17+
def make_array(*elements):
18+
"""Returns an array containing all the arguments passed to this function.
19+
A simple way to make an array with a few elements.
20+
21+
As with any array, all arguments should have the same type.
22+
23+
>>> make_array(0)
24+
array([0])
25+
>>> make_array(2, 3, 4)
26+
array([2, 3, 4])
27+
>>> make_array("foo", "bar")
28+
array(['foo', 'bar'],
29+
dtype='<U3')
30+
>>> make_array()
31+
array([], dtype=float64)
32+
"""
33+
return np.array(elements)
34+
35+
1736
def percentile(p, arr=None):
1837
"""Returns the pth percentile of the input array (the value that is at
1938
least as great as p% of the values in the array).

datascience/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '0.5.20'
1+
__version__ = '0.6.0'

0 commit comments

Comments
 (0)