99"""
1010
1111import re
12+ from collections .abc import Sequence
1213from datetime import timedelta
1314from functools import lru_cache
1415from pathlib import Path
@@ -99,7 +100,7 @@ def get_info_file(directory: Path) -> Path:
99100 """
100101 Locate the qq job info file in a directory.
101102
102- This function searches for files matching the `QQ_INFO_SUFFIX ` in the
103+ This function searches for files with suffix `CFG.suffixes.qq_info ` in the
103104 provided directory. It raises an error if none or multiple info files are found.
104105
105106 Args:
@@ -124,7 +125,7 @@ def get_info_files(directory: Path) -> list[Path]:
124125 """
125126 Retrieve all qq job info files in a directory.
126127
127- This function searches for files matching the `QQ_INFO_SUFFIX ` in the
128+ This function searches for files with suffix `CFG.suffixes.qq_info ` in the
128129 provided directory. The files are sorted by their last modification time
129130 (with the newest modified file being last in the list).
130131
@@ -140,6 +141,51 @@ def get_info_files(directory: Path) -> list[Path]:
140141 return sorted (info_files , key = lambda f : f .stat ().st_mtime )
141142
142143
144+ def get_array_file (directory : Path ) -> Path :
145+ """
146+ Located the qq array file in a directory.
147+
148+ This function searches for files with suffix `CFG.suffixes.qq_array` in the
149+ provided directory. It raises an error if none or multiple array files are found.
150+
151+ Args:
152+ directory (Path): The directory to search in.
153+
154+ Returns:
155+ Path: The Path object of the detected qq array file.
156+
157+ Raises:
158+ QQError: If no array file is found or multiple array files are detected.
159+ """
160+ array_files = get_array_files (directory )
161+ if len (array_files ) == 0 :
162+ raise QQError ("No qq array file found." )
163+ if len (array_files ) > 1 :
164+ raise QQError ("Multiple qq array files found." )
165+
166+ return array_files [0 ]
167+
168+
169+ def get_array_files (directory : Path ) -> list [Path ]:
170+ """
171+ Retrieve all qq array files in a directory.
172+
173+ This function searches for files with suffix `CFG.suffixes.qq_array` in the
174+ provided directory. The files are sorted by their last modification time
175+ (with the newest modified file being last in the list).
176+
177+ Args:
178+ directory (Path): The directory to search in.
179+
180+ Returns:
181+ list[Path]: A list of Path objects representing the detected qq array files.
182+ """
183+ array_files = get_files_with_suffix (directory , CFG .suffixes .qq_array )
184+ logger .debug (f"Detected the following qq array files: { array_files } ." )
185+
186+ return sorted (array_files , key = lambda f : f .stat ().st_mtime )
187+
188+
143189def get_info_file_from_job_id (job_id : str ) -> Path :
144190 """
145191 Get path to the qq info file corresponding to a job with the given ID.
@@ -766,3 +812,30 @@ def default_resubmit_from_hosts() -> str:
766812 # if no batch system is available
767813 except QQError :
768814 return "??? (no batch system detected)"
815+
816+
817+ def subset_indices (a : Sequence [str | Path ], b : Sequence [str | Path ]) -> list [int ]:
818+ """
819+ Return indices in *a* corresponding to each element of *b*.
820+
821+ *b* must be a subset of *a*; both lists are assumed to contain no
822+ duplicates.
823+
824+ Args:
825+ a (Sequence[str | Path]): The reference sequence of strings or Paths.
826+ b (Sequence[str | Path]): The query list whose elements must all appear in *a*.
827+
828+ Returns:
829+ list[int]: A list of the same length as *b* where the i-th entry is
830+ the index of `b[i]` in *a*.
831+
832+ Raises:
833+ QQError: If *b* contains elements not present in *a*.
834+ """
835+ index_of : dict [str | Path , int ] = {value : idx for idx , value in enumerate (a )}
836+
837+ missing : list [str | Path ] = [item for item in b if item not in index_of ]
838+ if missing :
839+ raise QQError (f"b is not a subset of a. Missing elements: { missing } ." )
840+
841+ return [index_of [item ] for item in b ]
0 commit comments