diff --git a/src/safeds/data/tabular/containers/_row.py b/src/safeds/data/tabular/containers/_row.py index 61b84331e..44f2b02d8 100644 --- a/src/safeds/data/tabular/containers/_row.py +++ b/src/safeds/data/tabular/containers/_row.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from collections.abc import Iterable, Iterator from hashlib import md5 from typing import Any @@ -22,6 +24,29 @@ class Row: The schema of the row. """ + # ------------------------------------------------------------------------------------------------------------------ + # Creation + # ------------------------------------------------------------------------------------------------------------------ + + @staticmethod + def from_dict(data: dict[str, Any]) -> Row: + """ + Create a row from a dictionary that maps column names to column values. + + Parameters + ---------- + data : dict[str, Any] + The data. + + Returns + ------- + row : Row + The generated row. + """ + row_frame = pd.DataFrame([data.values()], columns=list(data.keys())) + # noinspection PyProtectedMember + return Row(data.values(), Schema._from_dataframe(row_frame)) + # ------------------------------------------------------------------------------------------------------------------ # Dunder methods # ------------------------------------------------------------------------------------------------------------------ @@ -180,6 +205,21 @@ def count(self) -> int: """ return len(self._data) + # ------------------------------------------------------------------------------------------------------------------ + # Conversion + # ------------------------------------------------------------------------------------------------------------------ + + def to_dict(self) -> dict[str, Any]: + """ + Return a dictionary that maps column names to column values. + + Returns + ------- + data : dict[str, Any] + Dictionary representation of the row. + """ + return {column_name: self.get_value(column_name) for column_name in self.get_column_names()} + # ------------------------------------------------------------------------------------------------------------------ # IPython integration # ------------------------------------------------------------------------------------------------------------------ diff --git a/tests/safeds/data/tabular/containers/test_row.py b/tests/safeds/data/tabular/containers/test_row.py index a0ce2abca..92a3fba9d 100644 --- a/tests/safeds/data/tabular/containers/test_row.py +++ b/tests/safeds/data/tabular/containers/test_row.py @@ -6,6 +6,27 @@ from safeds.data.tabular.typing import ColumnType, Integer, Schema, String +class TestFromDict: + @pytest.mark.parametrize( + ("data", "expected"), + [ + ( + {}, + Row([]), + ), + ( + { + "a": 1, + "b": 2, + }, + Row([1, 2], schema=Schema({"a": Integer(), "b": Integer()})), + ), + ], + ) + def test_should_create_row_from_dict(self, data: dict[str, Any], expected: Row) -> None: + assert Row.from_dict(data) == expected + + class TestInit: @pytest.mark.parametrize( ("row", "expected"), @@ -209,3 +230,24 @@ class TestCount: ) def test_should_return_the_number_of_columns(self, row: Row, expected: int) -> None: assert row.count() == expected + + +class TestToDict: + @pytest.mark.parametrize( + ("row", "expected"), + [ + ( + Row([]), + {}, + ), + ( + Row([1, 2], schema=Schema({"a": Integer(), "b": Integer()})), + { + "a": 1, + "b": 2, + }, + ), + ], + ) + def test_should_return_dict_for_table(self, row: Row, expected: dict[str, Any]) -> None: + assert row.to_dict() == expected diff --git a/tests/safeds/data/tabular/containers/test_table.py b/tests/safeds/data/tabular/containers/test_table.py index e99922056..bc0106c72 100644 --- a/tests/safeds/data/tabular/containers/test_table.py +++ b/tests/safeds/data/tabular/containers/test_table.py @@ -24,7 +24,7 @@ class TestFromDict: ), ], ) - def test_should_create_table_from_dict(self, data: dict[str, Any], expected: Table) -> None: + def test_should_create_table_from_dict(self, data: dict[str, list[Any]], expected: Table) -> None: assert Table.from_dict(data) == expected def test_should_raise_if_columns_have_different_lengths(self) -> None: @@ -49,7 +49,7 @@ class TestToDict: ), ], ) - def test_should_return_dict_for_table(self, table: Table, expected: dict[str, Any]) -> None: + def test_should_return_dict_for_table(self, table: Table, expected: dict[str, list[Any]]) -> None: assert table.to_dict() == expected