<commit_before># -*- coding: utf-8 -*-
"""
===============================================================================
Container class for collection of `Bond`\ s (:mod:`sknano.core.atoms._bonds`)
===============================================================================

.. currentmodule:: sknano.core.atoms._bonds

"""
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals
from builtins import str
__docformat__ = 'restructuredtext en'

#from itertools import combinations
from operator import attrgetter

import numpy as np

from sknano.core import UserList, cyclic_pairs, dedupe
from sknano.core.math import vector as vec

import sknano.core.atoms
#from ._bond import Bond

__all__ = ['Bonds']


class Bonds(UserList):
    """Base class for collection of atom `Bond`\ s.

    Parameters
    ----------
    bonds : {None, sequence, `Bonds`}, optional
        if not `None`, then a list of `Bond` instance objects

    """
    def __init__(self, bonds=None):
        super().__init__(initlist=bonds)

    def __str__(self):
        """Return a nice string representation of `Bonds`."""
        return '\n'.join([str(bond) for bond in self])

    def __repr__(self):
        """Return the canonical string representation of `Bonds`."""
        return "Bonds({!r})".format(self.data)

    def sort(self, key=attrgetter('length'), reverse=False):
        super().sort(key=key, reverse=reverse)

    @property
    def Nbonds(self):
        """Number of `Bond`\ s in `Bonds`."""
        return len(self)

    @property
    def vectors(self):
        """:class:`~numpy:numpy.ndarray` of :attr:`~Bond.vector`\ s."""
        return np.asarray([bond.vector for bond in self])

    @property
    def unit_vectors(self):
        """:class:`~numpy:numpy.ndarray` of :attr:`~Bond.unit_vector`\ s."""
        return np.asarray([bond.unit_vector for bond in self])

    @property
    def lengths(self):
        """:class:`~numpy:numpy.ndarray` of :attr:`~Bond.length`\ s."""
        return np.asarray([bond.length for bond in self])

    @property
    def mean_length(self):
        """Mean bond length."""
        return np.mean(self.lengths)

    @property
    def bond_angle_pairs(self):
        """`cyclic_pairs` of `Bond`\ s."""
        return cyclic_pairs(self)

    @property
    def angles(self):
        """:class:`~numpy:numpy.ndarray` of `Bond` pair angles."""
        return np.asarray([vec.angle(b1.vector, b2.vector) for (b1, b2) in
                           cyclic_pairs(self)])

    @property
    def mean_angle(self):
        """Mean bond angle."""
        return np.mean(self.angles)

    @property
    def atoms(self):
        """`Atoms` :class:`python:set` in `Bonds`."""
        atoms = []
        [atoms.extend(bond.atoms) for bond in self]
        atoms = dedupe(atoms, key=attrgetter('id', 'x', 'y', 'z'))
        return sknano.core.atoms.StructureAtoms(atoms=list(atoms))<commit_msg>Refactoring `Bonds` class with the following changes...<commit_after># -*- coding: utf-8 -*-
"""
===============================================================================
Container class for collection of `Bond`\ s (:mod:`sknano.core.atoms._bonds`)
===============================================================================

.. currentmodule:: sknano.core.atoms._bonds

"""
from __future__ import absolute_import, division, print_function
from __future__ import unicode_literals
__docformat__ = 'restructuredtext en'

from operator import attrgetter

import numpy as np

from sknano.core import UserList, cyclic_pairs, dedupe
from sknano.core.math import vector as vec

import sknano.core.atoms

__all__ = ['Bonds']


class Bonds(UserList):
    """Base class for collection of atom `Bond`\ s.

    Parameters
    ----------
    bonds : {None, sequence, `Bonds`}, optional
        if not `None`, then a list of `Bond` instance objects

    """
    def __init__(self, bonds=None):
        super().__init__(initlist=bonds)
        self.fmtstr = "{bonds!r}"

    def __repr__(self):
        """Return canonical string representation of `Bonds`."""
        return "{}({})".format(self.__class__.__name__,
                               self.fmtstr.format(**self.todict()))

    def sort(self, key=attrgetter('length'), reverse=False):
        super().sort(key=key, reverse=reverse)

    # def __getitem__(self, index):
    #     data = super().__getitem__(index)
    #     if isinstance(data, list):
    #         return self.__class__(data)
    #     return data

    # def __setitem__(self, index, value):
    #     if not isinstance(value, (self.__class__, Bond)):
    #         if isinstance(index, slice):
    #             value = self.__class__(value)
    #         else:
    #             value = Bond(value)
    #     super().__setitem__(index, value)

    @property
    def fmtstr(self):
        return self._fmtstr

    @fmtstr.setter
    def fmtstr(self, value):
        self._fmtstr = value

    @property
    def Nbonds(self):
        """Number of `Bond`\ s in `Bonds`."""
        return len(self)

    @property
    def vectors(self):
        """:class:`~numpy:numpy.ndarray` of :attr:`~Bond.vector`\ s."""
        return np.asarray([bond.vector for bond in self])

    @property
    def unit_vectors(self):
        """:class:`~numpy:numpy.ndarray` of :attr:`~Bond.unit_vector`\ s."""
        return np.asarray([bond.unit_vector for bond in self])

    @property
    def lengths(self):
        """:class:`~numpy:numpy.ndarray` of :attr:`~Bond.length`\ s."""
        return np.asarray([bond.length for bond in self])

    @property
    def mean_length(self):
        """Mean bond length."""
        return np.mean(self.lengths)

    @property
    def bond_angle_pairs(self):
        """`cyclic_pairs` of `Bond`\ s."""
        return cyclic_pairs(self.data)

    @property
    def angles(self):
        """:class:`~numpy:numpy.ndarray` of `Bond` pair angles."""
        return np.asarray([vec.angle(b1.vector, b2.vector) for (b1, b2) in
                           cyclic_pairs(self)])

    @property
    def mean_angle(self):
        """Mean bond angle."""
        return np.mean(self.angles)

    @property
    def atoms(self):
        """`Atoms` :class:`python:set` in `Bonds`."""
        atoms = []
        [atoms.extend(bond.atoms) for bond in self]
        atoms = dedupe(atoms, key=attrgetter('id'))
        return sknano.core.atoms.StructureAtoms(list(atoms))

    def todict(self):
        return dict(bonds=self.data)
{'fraction_non_alphanumeric': 0.18794217163949553, 'fraction_numerical': 0.0015379883112888342, 'mean_word_length': 2.91040288634997, 'pattern_counts': {'":': 8, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1047720', 'n_tokens_mistral': 2054, 'n_tokens_neox': 1977, 'n_words': 495}