def gather_categories(imap, header, categories=None):
    if categories is None:
        return {"default": DataCategory(set(imap.keys()), {})}
    cat_ids = [header.index(cat)
               for cat in categories if cat in header and "=" not in cat]
    table = OrderedDict()
    conditions = defaultdict(set)
    for i, cat in enumerate(categories):
        if "=" in cat and cat.split("=")[0] in header:
            cat_name = header[header.index(cat.split("=")[0])]
            conditions[cat_name].add(cat.split("=")[1])
    if not cat_ids and not conditions:
        return {"default": DataCategory(set(imap.keys()), {})}
    if cat_ids and not conditions:
        for sid, row in imap.items():
            cat_name = "_".join([row[cid] for cid in cat_ids])
            if cat_name not in table:
                table[cat_name] = DataCategory(set(), {})
            table[cat_name].sids.add(sid)
        return table
    cond_ids = set()
    for k in conditions:
        try:
            cond_ids.add(header.index(k))
        except ValueError:
            continue
    idx_to_test = set(cat_ids).union(cond_ids)
    for sid, row in imap.items():
        if all([row[header.index(c)] in conditions[c] for c in conditions]):
            key = "_".join([row[idx] for idx in idx_to_test])
            try:
                assert key in table.keys()
            except AssertionError:
                table[key] = DataCategory(set(), {})
            table[key].sids.add(sid)
    try:
        assert len(table) > 0
    except AssertionError:
        return {"default": DataCategory(set(imap.keys()), {})}
    else:
        return table