SEMI-ADVANCED SLICE() EXAMPLES
Python
#!/usr/bin/env python3
"""
SEMI-ADVANCED SLICE() EXAMPLES
Advanced patterns, custom classes, and optimization techniques
"""
print("=" * 60)
print("SEMI-ADVANCED SLICE() - Advanced Slicing Techniques")
print("=" * 60)
# Example 1: The indices() method
print("\n1. Understanding slice.indices()")
print("-" * 40)
print("indices(len) normalizes slice to actual indices\n")
data = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(f"Data: {data} (length: {len(data)})\n")
slices_to_test = [
slice(2, 8, 2),
slice(-5, -1),
slice(None, None, 2),
slice(100), # Beyond length
slice(-100, 100), # Beyond both ends
]
for s in slices_to_test:
start, stop, step = s.indices(len(data))
result = data[s]
print(f"slice{s.start, s.stop, s.step}:")
print(f" indices() returns: ({start}, {stop}, {step})")
print(f" Result: {result}\n")
# Example 2: Custom class with slice support
print("\n2. Custom Class with Slicing Support")
print("-" * 40)
class TimeSeriesData:
def __init__(self, data, labels):
self.data = data
self.labels = labels
def __getitem__(self, key):
if isinstance(key, slice):
return TimeSeriesData(
self.data[key],
self.labels[key]
)
return self.data[key]
def __repr__(self):
pairs = [f"{label}:{value}" for label, value in zip(self.labels, self.data)]
return f"TimeSeriesData([{', '.join(pairs)}])"
def __len__(self):
return len(self.data)
# Create time series
ts = TimeSeriesData(
data=[100, 105, 110, 108, 112, 115, 118, 120],
labels=['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug']
)
print(f"Original: {ts}\n")
print(f"First half (slice(4)): {ts[slice(4)]}")
print(f"Every other (slice(None, None, 2)): {ts[slice(None, None, 2)]}")
print(f"Last 3 (slice(-3, None)): {ts[slice(-3, None)]}")
# Example 3: Slice composition and transformation
print("\n3. Composing and Transforming Slices")
print("-" * 40)
def combine_slices(s1, s2, length):
"""Apply s2 to the result of s1"""
start1, stop1, step1 = s1.indices(length)
# Length after first slice
new_length = len(range(start1, stop1, step1))
# Apply second slice
start2, stop2, step2 = s2.indices(new_length)
# Transform indices
indices = range(start1, stop1, step1)
sub_indices = list(indices)[start2:stop2:step2]
return sub_indices
data = list(range(20))
print(f"Data: {data}\n")
s1 = slice(5, 15) # Get middle section
s2 = slice(None, None, 2) # Every other
result_indices = combine_slices(s1, s2, len(data))
print(f"First slice(5, 15): {data[s1]}")
print(f"Then slice(None, None, 2) on result: {[data[i] for i in result_indices]}")
# Example 4: Circular buffer with slicing
print("\n4. Circular Buffer Implementation")
print("-" * 40)
class CircularBuffer:
def __init__(self, size):
self.size = size
self.buffer = [None] * size
self.position = 0
self.count = 0
def append(self, item):
self.buffer[self.position] = item
self.position = (self.position + 1) % self.size
self.count = min(self.count + 1, self.size)
def __getitem__(self, key):
if isinstance(key, slice):
# Get valid indices
start, stop, step = key.indices(self.count)
result = []
for i in range(start, stop, step):
# Map logical index to buffer position
actual_pos = (self.position - self.count + i) % self.size
result.append(self.buffer[actual_pos])
return result
else:
actual_pos = (self.position - self.count + key) % self.size
return self.buffer[actual_pos]
def __len__(self):
return self.count
# Demo circular buffer
cb = CircularBuffer(5)
for i in range(8):
cb.append(f"Item{i}")
print(f"Added Item{i}, buffer state: {cb[slice(None)]}")
print(f"\nFinal buffer:")
print(f" Full view: {cb[slice(None)]}")
print(f" Last 3: {cb[slice(-3, None)]}")
print(f" Every other: {cb[slice(None, None, 2)]}")
# Example 5: Efficient slice-based filtering
print("\n5. Slice-Based Data Filtering Pipeline")
print("-" * 40)
class DataFilter:
def __init__(self, data):
self.data = data
self.slices = []
def skip_first(self, n):
"""Skip first n elements"""
self.slices.append(('skip_first', slice(n, None)))
return self
def take(self, n):
"""Take only n elements"""
self.slices.append(('take', slice(n)))
return self
def every_nth(self, n):
"""Take every nth element"""
self.slices.append(('every_nth', slice(None, None, n)))
return self
def execute(self):
"""Apply all slices in order"""
result = self.data
for name, s in self.slices:
result = result[s]
print(f" After {name}: {result}")
return result
data = list(range(1, 51))
print(f"Original data: {data[:10]}...{data[-5:]} (1-50)\n")
print("Applying filters:")
filtered = DataFilter(data).skip_first(10).every_nth(3).take(5).execute()
print(f"\nFinal result: {filtered}")
# Example 6: Slicing with assignment
print("\n6. Slice Assignment and Modification")
print("-" * 40)
data = list(range(10))
print(f"Original: {data}")
# Replace middle section
middle = slice(3, 7)
data[middle] = [99, 88, 77, 66]
print(f"Replace [3:7]: {data}")
# Insert elements (replace 0-length slice)
data = list(range(10))
insert_at = slice(5, 5)
data[insert_at] = [100, 200]
print(f"Insert at 5: {data}")
# Delete elements
data = list(range(10))
delete_range = slice(2, 5)
data[delete_range] = []
print(f"Delete [2:5]: {data}")
# Replace with different length
data = list(range(10))
replace_slice = slice(3, 6)
data[replace_slice] = [111, 222, 333, 444, 555] # More elements
print(f"Replace with more: {data}")
# Example 7: Memory-efficient iteration with slices
print("\n7. Processing Large Data in Chunks")
print("-" * 40)
def process_in_chunks(data, chunk_size, processor):
"""Process data in chunks without creating sublists"""
results = []
for i in range(0, len(data), chunk_size):
chunk_slice = slice(i, min(i + chunk_size, len(data)))
chunk_result = processor(data[chunk_slice])
results.append(chunk_result)
return results
# Simulate large dataset
large_data = list(range(1, 101))
# Process in chunks of 10
chunk_sums = process_in_chunks(
large_data,
chunk_size=10,
processor=sum
)
print(f"Data size: {len(large_data)} elements")
print(f"Chunk size: 10")
print(f"Chunk sums: {chunk_sums}")
print(f"Total sum: {sum(chunk_sums)}")
# Example 8: Advanced slice arithmetic
print("\n8. Slice Range Calculations")
print("-" * 40)
def slice_length(s, sequence_length):
"""Calculate how many elements a slice will return"""
start, stop, step = s.indices(sequence_length)
return len(range(start, stop, step))
def slices_overlap(s1, s2, sequence_length):
"""Check if two slices overlap"""
start1, stop1, _ = s1.indices(sequence_length)
start2, stop2, _ = s2.indices(sequence_length)
range1 = set(range(start1, stop1))
range2 = set(range(start2, stop2))
return bool(range1 & range2)
length = 20
s1 = slice(5, 15)
s2 = slice(10, 18)
s3 = slice(16, 20)
print(f"Sequence length: {length}")
print(f"Slice 1: slice(5, 15)")
print(f" Length: {slice_length(s1, length)}")
print(f"Slice 2: slice(10, 18)")
print(f" Length: {slice_length(s2, length)}")
print(f"\nDo slice(5, 15) and slice(10, 18) overlap?")
print(f" {slices_overlap(s1, s2, length)}")
print(f"Do slice(5, 15) and slice(16, 20) overlap?")
print(f" {slices_overlap(s1, s3, length)}")
# Example 9: Lazy evaluation with slices
print("\n9. Lazy Slice Evaluation")
print("-" * 40)
class LazySliceView:
"""View of data that doesn't copy until needed"""
def __init__(self, data, slice_obj=None):
self.data = data
self.slice_obj = slice_obj or slice(None)
def __getitem__(self, key):
if isinstance(key, slice):
# Create new view by composing slices
return LazySliceView(self.data, key)
# Evaluate on access
start, stop, step = self.slice_obj.indices(len(self.data))
indices = range(start, stop, step)
return self.data[list(indices)[key]]
def materialize(self):
"""Convert view to actual list"""
return self.data[self.slice_obj]
def __repr__(self):
return f"LazySliceView(slice{self.slice_obj.start, self.slice_obj.stop, self.slice_obj.step})"
large_data = list(range(1000))
view = LazySliceView(large_data)
print(f"Created view of {len(large_data)} elements")
print(f"View: {view}")
subset = view[100:200]
print(f"Created subset view: {subset}")
final = subset[::10]
print(f"Created final view (every 10th): {final}")
print(f"Materialized result: {final.materialize()}")
# Example 10: Slice validation and sanitization
print("\n10. Slice Validation Helper")
print("-" * 40)
def validate_and_fix_slice(s, length, name="slice"):
"""Validate slice and return normalized version"""
issues = []
start, stop, step = s.indices(length)
# Check for empty result
if start >= stop and step > 0:
issues.append(f"Empty slice: start({start}) >= stop({stop})")
elif start <= stop and step < 0:
issues.append(f"Empty slice: start({start}) <= stop({stop}) with negative step")
# Check for step=0
if s.step == 0:
issues.append("Invalid: step cannot be 0")
# Report original vs normalized
if (s.start, s.stop, s.step) != (start, stop, step):
issues.append(f"Normalized from ({s.start}, {s.stop}, {s.step}) to ({start}, {stop}, {step})")
if issues:
print(f"{name}:")
for issue in issues:
print(f" - {issue}")
else:
print(f"{name}: OK")
return slice(start, stop, step)
test_slices = [
(slice(5, 10), "Normal slice"),
(slice(100, 200), "Beyond bounds"),
(slice(-5, None), "Negative start"),
(slice(10, 5), "Backwards (positive step)"),
(slice(None, None, -2), "Negative step"),
]
for s, name in test_slices:
validate_and_fix_slice(s, 20, name)
print("\n" + "=" * 60)
print("Advanced Concepts:")
print(" - slice.indices(len) normalizes to actual indices")
print(" - Implement __getitem__ for custom slicing behavior")
print(" - Slice composition for complex transformations")
print(" - Lazy evaluation avoids unnecessary copying")
print(" - Slice assignment: data[s] = new_values")
print(" - Validate slices before applying to avoid errors")
print("=" * 60)