Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Program to find the resolved Unix style path in Python
In Unix systems, paths can contain special directory symbols: ".." represents the parent directory and "." represents the current directory. When given a path as a list of strings, we need to resolve these symbols to find the actual final path.
For example, if we have ["usr", "..", "usr", ".", "local", "etc", "foo"], this represents the path /usr/../usr/./local/etc/foo which resolves to /usr/local/etc/foo.
Algorithm
The solution uses a stack-based approach ?
- Create an empty stack (list) to store resolved path components
- For each element in the path:
- If element is
"..": pop from stack (go to parent directory) if stack is not empty - If element is
".": ignore it (stay in current directory) - Otherwise: append element to stack (enter this directory)
- If element is
- Return the stack as the resolved path
Implementation
class Solution:
def solve(self, path):
resolved_path = []
for component in path:
if component == '..':
if len(resolved_path) > 0:
resolved_path.pop()
elif component != '.':
resolved_path.append(component)
return resolved_path
# Example usage
solution = Solution()
path = ["usr", "..", "usr", ".", "local", "etc", "foo"]
result = solution.solve(path)
print("Input path:", path)
print("Resolved path:", result)
Input path: ['usr', '..', 'usr', '.', 'local', 'etc', 'foo'] Resolved path: ['usr', 'local', 'etc', 'foo']
How It Works
Let's trace through the example step by step ?
def trace_resolution(path):
resolved_path = []
for i, component in enumerate(path):
print(f"Step {i+1}: Processing '{component}'")
if component == '..':
if len(resolved_path) > 0:
removed = resolved_path.pop()
print(f" Going back from '{removed}'")
else:
print(" Already at root, ignoring '..'")
elif component != '.':
resolved_path.append(component)
print(f" Entering directory '{component}'")
else:
print(" Staying in current directory")
print(f" Current path: {resolved_path}")
print()
return resolved_path
path = ["usr", "..", "usr", ".", "local", "etc", "foo"]
result = trace_resolution(path)
print(f"Final resolved path: {result}")
Step 1: Processing 'usr' Entering directory 'usr' Current path: ['usr'] Step 2: Processing '..' Going back from 'usr' Current path: [] Step 3: Processing 'usr' Entering directory 'usr' Current path: ['usr'] Step 4: Processing '.' Staying in current directory Current path: ['usr'] Step 5: Processing 'local' Entering directory 'local' Current path: ['usr', 'local'] Step 6: Processing 'etc' Entering directory 'etc' Current path: ['usr', 'local', 'etc'] Step 7: Processing 'foo' Entering directory 'foo' Current path: ['usr', 'local', 'etc', 'foo'] Final resolved path: ['usr', 'local', 'etc', 'foo']
Edge Cases
The algorithm handles common edge cases ?
solution = Solution()
# Test cases
test_cases = [
["..", "usr", "local"], # Starting with parent directory
["usr", ".", ".", "local"], # Multiple current directory symbols
["usr", "local", "..", "..", "etc"], # Multiple parent directories
[".", "..", "."], # Only special symbols
]
for i, test_path in enumerate(test_cases):
result = solution.solve(test_path)
print(f"Test {i+1}: {test_path}")
print(f"Result: {result}")
print()
Test 1: ['..', 'usr', 'local'] Result: ['usr', 'local'] Test 2: ['usr', '.', '.', 'local'] Result: ['usr', 'local'] Test 3: ['usr', 'local', '..', '..', 'etc'] Result: ['etc'] Test 4: ['.', '..', '.'] Result: []
Conclusion
This stack-based approach efficiently resolves Unix-style paths by processing each component sequentially. The algorithm handles parent directory navigation with ".." and ignores current directory references with ".", returning the final resolved path as a list.
