Repository: Project-MONAI/MONAI

Issue:
Select Items Dictionary Transform
**Problem**
Currently, the only way to remove dictionary keys it to remove them with the `DeleteItemsd` transform. Though this solves the problem it is not the most elegant way to do it. For example, suppose you have numerous different NIfTI files and use the pipeline to combined them into a single channels wise input. In this case, I find that selecting what you want to keep is more elegant (and less prone to error) then listing everything you want to remove.

**The solution**
A transform with the same workings as `DeleteItemsd` but which includes instead of excludes.



Discussion:

Resolving patch:
diff --git a/monai/transforms/utility/dictionary.py b/monai/transforms/utility/dictionary.py
--- a/monai/transforms/utility/dictionary.py
+++ b/monai/transforms/utility/dictionary.py
@@ -247,6 +247,25 @@ def __call__(self, data):
         return {key: val for key, val in data.items() if key not in self.keys}
 
 
+class SelectItemsd(MapTransform):
+    """
+    Select only specified items from data dictionary to release memory.
+    It will copy the selected key-values and construct and new dictionary.
+    """
+
+    def __init__(self, keys):
+        """
+        Args:
+            keys: keys of the corresponding items to be transformed.
+                See also: :py:class:`monai.transforms.compose.MapTransform`
+        """
+        super().__init__(keys)
+
+    def __call__(self, data):
+        result = {key: val for key, val in data.items() if key in self.keys}
+        return result
+
+
 class SqueezeDimd(MapTransform):
     """
     Dictionary-based wrapper of :py:class:`monai.transforms.SqueezeDim`.


Test patch:
diff --git a/tests/test_select_itemsd.py b/tests/test_select_itemsd.py
new file mode 100644
--- /dev/null
+++ b/tests/test_select_itemsd.py
@@ -0,0 +1,38 @@
+# Copyright 2020 MONAI Consortium
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#     http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import sys
+import time
+import unittest
+
+from parameterized import parameterized
+
+from monai.transforms import SelectItemsd
+
+TEST_CASE_1 = [{"keys": [str(i) for i in range(30)]}, 30]
+
+
+class TestSelectItemsd(unittest.TestCase):
+    @parameterized.expand([TEST_CASE_1])
+    def test_memory(self, input_param, expected_key_size):
+        input_data = dict()
+        for i in range(50):
+            input_data[str(i)] = [time.time()] * 100000
+        result = SelectItemsd(**input_param)(input_data)
+        self.assertEqual(len(result.keys()), expected_key_size)
+        self.assertSetEqual(set(result.keys()), set(input_param["keys"]))
+        self.assertGreaterEqual(
+            sys.getsizeof(input_data) * float(expected_key_size) / len(input_data), sys.getsizeof(result)
+        )
+
+
+if __name__ == "__main__":
+    unittest.main()