Efficient way of flat mapping a range of a multidimensional random access collectionPartitioning array...
Why is this code 6.5x slower with optimizations enabled?
Are white and non-white police officers equally likely to kill black suspects?
New order #4: World
How can bays and straits be determined in a procedurally generated map?
Can Medicine checks be used, with decent rolls, to completely mitigate the risk of death from ongoing damage?
Is there a minimum number of transactions in a block?
DOS, create pipe for stdin/stdout of command.com(or 4dos.com) in C or Batch?
How to report a triplet of septets in NMR tabulation?
What would happen to a modern skyscraper if it rains micro blackholes?
How is the claim "I am in New York only if I am in America" the same as "If I am in New York, then I am in America?
How does one intimidate enemies without having the capacity for violence?
I’m planning on buying a laser printer but concerned about the life cycle of toner in the machine
I probably found a bug with the sudo apt install function
What makes Graph invariants so useful/important?
Schwarzchild Radius of the Universe
How to calculate implied correlation via observed market price (Margrabe option)
What defenses are there against being summoned by the Gate spell?
Is it possible to make sharp wind that can cut stuff from afar?
Why did the Germans forbid the possession of pet pigeons in Rostov-on-Don in 1941?
What Brexit solution does the DUP want?
declaring a variable twice in IIFE
least quadratic residue under GRH: an EXPLICIT bound
Is it possible to do 50 km distance without any previous training?
Can I make popcorn with any corn?
Efficient way of flat mapping a range of a multidimensional random access collection
Partitioning array elements into two subsetsBuilding a histogram array in PHPCount the accumulated rainfall in a 2D mountain rangeUsing 2D arrays to make more efficient sequential storageFind the max. difference between two array elements a[j] and a[i] such that j > iFinding an equilibrium index in an int arrayCalculating sum after ranged-based subtractionsprint array of previous smaller elementsShuffling an array keeping some elements fixedUse arrays to perform 'VLookUp' type activity between workbooks
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ margin-bottom:0;
}
$begingroup$
I've recently answered a question about reading elements from an array of arrays. A way it could be interpreted is that the OP wanted to read a range that could span over multiple subarrays of the 2D array like so :
let a = [["5", "3", ".", ".", "7", "."],
["6", ".", ".", "1", "9", "5"]]
a.lazy.flatMap{$0}[1..<7] ["3", ".", ".", "7", ".", "6"]
This way of reading a range would need to at least flatMap
all the previous arrays to the lower bound of the range. Which would be wasteful.
A more natural way would be to only read the needed elements from the original array:
func get<T>(_ range: Range<Int>, from array2d: [[T]]) -> [T]? {
var result: [T] = []
result.reserveCapacity(range.upperBound - range.lowerBound)
var count1 = 0
//Get the index of the first element
guard var low = array2d
.firstIndex(where: {
count1 += $0.count
return range.lowerBound < count1 }),
count1 != 0
else { return nil }
let before = count1 - array2d[low].count
var count2 = before
//Get the index of the last element in the range
guard let high = array2d[low..<array2d.endIndex]
.firstIndex(where: {
count2 += $0.count
return range.upperBound <= count2
}),
count2 != 0
else { return nil }
//Append the elements in the array with the low index
for i in (range.lowerBound - before)..<min(range.upperBound - before, array2d[low].count) {
result.append(array2d[low][i])
}
//If the range spans over multiple arrays
if count1 < count2 {
low += 1
//Append the elements in the arrays with an index between low and high
while low < high {
result.append(contentsOf: array2d[low])
low += 1
}
//Append the elements in the array with the high index
for i in 0..<(range.upperBound - count2 + array2d[high].count) {
result.append(array2d[high][i])
}
}
return result
}
Which could be used like so :
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
get(5..<11, from: a) //Optional(["5", "6", "7", "8", "9", "10"])
get(7..<9, from: a) //Optional(["7", "8"])
To me, the above code feels.. on the border of sanity/maintainability...
What I'd like to do is to make it more generic, maybe as an extension to RandomAccessCollection
, and making the flattening process recursive for arrays/collections of arbitrary dimensions. I'm stuck here and not sure if this is the appropriate network to ask such a question.
Feedback on all aspects of the code is welcome, such as (but not limited to):
- Efficiency,
- Readability,
- Naming.
performance array swift collections
$endgroup$
add a comment |
$begingroup$
I've recently answered a question about reading elements from an array of arrays. A way it could be interpreted is that the OP wanted to read a range that could span over multiple subarrays of the 2D array like so :
let a = [["5", "3", ".", ".", "7", "."],
["6", ".", ".", "1", "9", "5"]]
a.lazy.flatMap{$0}[1..<7] ["3", ".", ".", "7", ".", "6"]
This way of reading a range would need to at least flatMap
all the previous arrays to the lower bound of the range. Which would be wasteful.
A more natural way would be to only read the needed elements from the original array:
func get<T>(_ range: Range<Int>, from array2d: [[T]]) -> [T]? {
var result: [T] = []
result.reserveCapacity(range.upperBound - range.lowerBound)
var count1 = 0
//Get the index of the first element
guard var low = array2d
.firstIndex(where: {
count1 += $0.count
return range.lowerBound < count1 }),
count1 != 0
else { return nil }
let before = count1 - array2d[low].count
var count2 = before
//Get the index of the last element in the range
guard let high = array2d[low..<array2d.endIndex]
.firstIndex(where: {
count2 += $0.count
return range.upperBound <= count2
}),
count2 != 0
else { return nil }
//Append the elements in the array with the low index
for i in (range.lowerBound - before)..<min(range.upperBound - before, array2d[low].count) {
result.append(array2d[low][i])
}
//If the range spans over multiple arrays
if count1 < count2 {
low += 1
//Append the elements in the arrays with an index between low and high
while low < high {
result.append(contentsOf: array2d[low])
low += 1
}
//Append the elements in the array with the high index
for i in 0..<(range.upperBound - count2 + array2d[high].count) {
result.append(array2d[high][i])
}
}
return result
}
Which could be used like so :
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
get(5..<11, from: a) //Optional(["5", "6", "7", "8", "9", "10"])
get(7..<9, from: a) //Optional(["7", "8"])
To me, the above code feels.. on the border of sanity/maintainability...
What I'd like to do is to make it more generic, maybe as an extension to RandomAccessCollection
, and making the flattening process recursive for arrays/collections of arbitrary dimensions. I'm stuck here and not sure if this is the appropriate network to ask such a question.
Feedback on all aspects of the code is welcome, such as (but not limited to):
- Efficiency,
- Readability,
- Naming.
performance array swift collections
$endgroup$
add a comment |
$begingroup$
I've recently answered a question about reading elements from an array of arrays. A way it could be interpreted is that the OP wanted to read a range that could span over multiple subarrays of the 2D array like so :
let a = [["5", "3", ".", ".", "7", "."],
["6", ".", ".", "1", "9", "5"]]
a.lazy.flatMap{$0}[1..<7] ["3", ".", ".", "7", ".", "6"]
This way of reading a range would need to at least flatMap
all the previous arrays to the lower bound of the range. Which would be wasteful.
A more natural way would be to only read the needed elements from the original array:
func get<T>(_ range: Range<Int>, from array2d: [[T]]) -> [T]? {
var result: [T] = []
result.reserveCapacity(range.upperBound - range.lowerBound)
var count1 = 0
//Get the index of the first element
guard var low = array2d
.firstIndex(where: {
count1 += $0.count
return range.lowerBound < count1 }),
count1 != 0
else { return nil }
let before = count1 - array2d[low].count
var count2 = before
//Get the index of the last element in the range
guard let high = array2d[low..<array2d.endIndex]
.firstIndex(where: {
count2 += $0.count
return range.upperBound <= count2
}),
count2 != 0
else { return nil }
//Append the elements in the array with the low index
for i in (range.lowerBound - before)..<min(range.upperBound - before, array2d[low].count) {
result.append(array2d[low][i])
}
//If the range spans over multiple arrays
if count1 < count2 {
low += 1
//Append the elements in the arrays with an index between low and high
while low < high {
result.append(contentsOf: array2d[low])
low += 1
}
//Append the elements in the array with the high index
for i in 0..<(range.upperBound - count2 + array2d[high].count) {
result.append(array2d[high][i])
}
}
return result
}
Which could be used like so :
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
get(5..<11, from: a) //Optional(["5", "6", "7", "8", "9", "10"])
get(7..<9, from: a) //Optional(["7", "8"])
To me, the above code feels.. on the border of sanity/maintainability...
What I'd like to do is to make it more generic, maybe as an extension to RandomAccessCollection
, and making the flattening process recursive for arrays/collections of arbitrary dimensions. I'm stuck here and not sure if this is the appropriate network to ask such a question.
Feedback on all aspects of the code is welcome, such as (but not limited to):
- Efficiency,
- Readability,
- Naming.
performance array swift collections
$endgroup$
I've recently answered a question about reading elements from an array of arrays. A way it could be interpreted is that the OP wanted to read a range that could span over multiple subarrays of the 2D array like so :
let a = [["5", "3", ".", ".", "7", "."],
["6", ".", ".", "1", "9", "5"]]
a.lazy.flatMap{$0}[1..<7] ["3", ".", ".", "7", ".", "6"]
This way of reading a range would need to at least flatMap
all the previous arrays to the lower bound of the range. Which would be wasteful.
A more natural way would be to only read the needed elements from the original array:
func get<T>(_ range: Range<Int>, from array2d: [[T]]) -> [T]? {
var result: [T] = []
result.reserveCapacity(range.upperBound - range.lowerBound)
var count1 = 0
//Get the index of the first element
guard var low = array2d
.firstIndex(where: {
count1 += $0.count
return range.lowerBound < count1 }),
count1 != 0
else { return nil }
let before = count1 - array2d[low].count
var count2 = before
//Get the index of the last element in the range
guard let high = array2d[low..<array2d.endIndex]
.firstIndex(where: {
count2 += $0.count
return range.upperBound <= count2
}),
count2 != 0
else { return nil }
//Append the elements in the array with the low index
for i in (range.lowerBound - before)..<min(range.upperBound - before, array2d[low].count) {
result.append(array2d[low][i])
}
//If the range spans over multiple arrays
if count1 < count2 {
low += 1
//Append the elements in the arrays with an index between low and high
while low < high {
result.append(contentsOf: array2d[low])
low += 1
}
//Append the elements in the array with the high index
for i in 0..<(range.upperBound - count2 + array2d[high].count) {
result.append(array2d[high][i])
}
}
return result
}
Which could be used like so :
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
get(5..<11, from: a) //Optional(["5", "6", "7", "8", "9", "10"])
get(7..<9, from: a) //Optional(["7", "8"])
To me, the above code feels.. on the border of sanity/maintainability...
What I'd like to do is to make it more generic, maybe as an extension to RandomAccessCollection
, and making the flattening process recursive for arrays/collections of arbitrary dimensions. I'm stuck here and not sure if this is the appropriate network to ask such a question.
Feedback on all aspects of the code is welcome, such as (but not limited to):
- Efficiency,
- Readability,
- Naming.
performance array swift collections
performance array swift collections
edited Apr 3 at 9:29
ielyamani
asked Apr 1 at 13:47
ielyamaniielyamani
372213
372213
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
I gather that your intent was to write a method that iterates through an array of arrays (but avoiding functional patterns), flattening the results in the process such that given...
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
... that result for 5..<10
would be ["5", "6", "7", "8", "9"]
Assuming that’s what you were trying to do, I think you can simplify it:
extension Array {
func flattened<T>(range: Range<Int>) -> [T]? where Element == Array<T> {
var result: [T] = []
var offset = range.startIndex
var length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for subarray in self {
let subarrayCount = subarray.count
if offset < subarrayCount {
if length > subarrayCount - offset {
result += subarray[offset...]
length -= subarrayCount - offset
} else {
return result + subarray[offset..<offset + length]
}
}
offset = Swift.max(0, offset - subarrayCount)
}
return nil
}
}
In terms of observations on your code:
I wouldn’t advise
get
method name. It’s not very meaningful name and only conjures up confusion with getters. I’d go with something that captured the “flattening” nature of the routine.As a general rule, we should avoid closures with side-effects in functional programming patterns. Even though you’ve written an “iterative” rendition of the OP’s code, you’re using a functional method,
firstIndex
, and you are updating variables outside the closure. It’s technically allowed but is contrary to the spirit of functional programming patterns and is dependent upon the implementation details offirstIndex
.
$endgroup$
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
add a comment |
$begingroup$
Extensibility
The following is meant as an addendum to Rob's answer. It is built upon their approach and extends it to work for arrays with arbitrary depth.
extension Array {
func flattened(range: Range<Int>) -> [Any]? {
return helper(range).result?.count == range.upperBound - range.lowerBound ?
helper(range).result :
nil
}
private func helper(_ range: Range<Int>) -> (result: [Any]?, offset: Int) {
var result: [Any] = []
var offset = range.startIndex
let length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for i in self.indices {
let element = self[i]
if let sub_a: [Any] = element as? [Any] {
let tempo = sub_a.helper(offset..<offset + length - result.count)
if let res = tempo.result {
result += res
offset = tempo.offset
} else {
return (result: nil, offset: offset)
}
} else {
if offset == 0 {
result.append(element)
}
offset = Swift.max(0, offset - 1)
}
if result.count == length {
return (result: result, offset: offset)
}
}
return (result: result, offset: offset)
}
}
It has been tested with all of these arrays :
let a: [Any] = [[["0", "1", "2", "3", "4", "5"], ["6", "7"], []],
[["8", "9", "10", "11", "12"], ["13", "14", "15"]]]
let b: [Any] = [[["0", "1"], ["2", "3", "4"]],
[[]],
[["5"], ["6", "7", "8", "9"]],
[["10", "11", "12"], ["13", "14", "15"]]]
let c: [Any] = [["0", "1", "2", "3", "4", "5", ["6", "7", ["8", "9", "10", "11", "12"]]], [], ["13", "14", "15"]]
The output of all three :
print(a.flattened(range: 3..<15))
print(b.flattened(range: 3..<15))
print(c.flattened(range: 3..<15))
is
Optional(["3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"])
$endgroup$
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216657%2fefficient-way-of-flat-mapping-a-range-of-a-multidimensional-random-access-collec%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
I gather that your intent was to write a method that iterates through an array of arrays (but avoiding functional patterns), flattening the results in the process such that given...
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
... that result for 5..<10
would be ["5", "6", "7", "8", "9"]
Assuming that’s what you were trying to do, I think you can simplify it:
extension Array {
func flattened<T>(range: Range<Int>) -> [T]? where Element == Array<T> {
var result: [T] = []
var offset = range.startIndex
var length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for subarray in self {
let subarrayCount = subarray.count
if offset < subarrayCount {
if length > subarrayCount - offset {
result += subarray[offset...]
length -= subarrayCount - offset
} else {
return result + subarray[offset..<offset + length]
}
}
offset = Swift.max(0, offset - subarrayCount)
}
return nil
}
}
In terms of observations on your code:
I wouldn’t advise
get
method name. It’s not very meaningful name and only conjures up confusion with getters. I’d go with something that captured the “flattening” nature of the routine.As a general rule, we should avoid closures with side-effects in functional programming patterns. Even though you’ve written an “iterative” rendition of the OP’s code, you’re using a functional method,
firstIndex
, and you are updating variables outside the closure. It’s technically allowed but is contrary to the spirit of functional programming patterns and is dependent upon the implementation details offirstIndex
.
$endgroup$
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
add a comment |
$begingroup$
I gather that your intent was to write a method that iterates through an array of arrays (but avoiding functional patterns), flattening the results in the process such that given...
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
... that result for 5..<10
would be ["5", "6", "7", "8", "9"]
Assuming that’s what you were trying to do, I think you can simplify it:
extension Array {
func flattened<T>(range: Range<Int>) -> [T]? where Element == Array<T> {
var result: [T] = []
var offset = range.startIndex
var length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for subarray in self {
let subarrayCount = subarray.count
if offset < subarrayCount {
if length > subarrayCount - offset {
result += subarray[offset...]
length -= subarrayCount - offset
} else {
return result + subarray[offset..<offset + length]
}
}
offset = Swift.max(0, offset - subarrayCount)
}
return nil
}
}
In terms of observations on your code:
I wouldn’t advise
get
method name. It’s not very meaningful name and only conjures up confusion with getters. I’d go with something that captured the “flattening” nature of the routine.As a general rule, we should avoid closures with side-effects in functional programming patterns. Even though you’ve written an “iterative” rendition of the OP’s code, you’re using a functional method,
firstIndex
, and you are updating variables outside the closure. It’s technically allowed but is contrary to the spirit of functional programming patterns and is dependent upon the implementation details offirstIndex
.
$endgroup$
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
add a comment |
$begingroup$
I gather that your intent was to write a method that iterates through an array of arrays (but avoiding functional patterns), flattening the results in the process such that given...
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
... that result for 5..<10
would be ["5", "6", "7", "8", "9"]
Assuming that’s what you were trying to do, I think you can simplify it:
extension Array {
func flattened<T>(range: Range<Int>) -> [T]? where Element == Array<T> {
var result: [T] = []
var offset = range.startIndex
var length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for subarray in self {
let subarrayCount = subarray.count
if offset < subarrayCount {
if length > subarrayCount - offset {
result += subarray[offset...]
length -= subarrayCount - offset
} else {
return result + subarray[offset..<offset + length]
}
}
offset = Swift.max(0, offset - subarrayCount)
}
return nil
}
}
In terms of observations on your code:
I wouldn’t advise
get
method name. It’s not very meaningful name and only conjures up confusion with getters. I’d go with something that captured the “flattening” nature of the routine.As a general rule, we should avoid closures with side-effects in functional programming patterns. Even though you’ve written an “iterative” rendition of the OP’s code, you’re using a functional method,
firstIndex
, and you are updating variables outside the closure. It’s technically allowed but is contrary to the spirit of functional programming patterns and is dependent upon the implementation details offirstIndex
.
$endgroup$
I gather that your intent was to write a method that iterates through an array of arrays (but avoiding functional patterns), flattening the results in the process such that given...
let a = [["0", "1", "2", "3", "4", "5"], ["6", "7"], [], ["8","9","10","11", "12"], ["13","14", "15"]]
... that result for 5..<10
would be ["5", "6", "7", "8", "9"]
Assuming that’s what you were trying to do, I think you can simplify it:
extension Array {
func flattened<T>(range: Range<Int>) -> [T]? where Element == Array<T> {
var result: [T] = []
var offset = range.startIndex
var length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for subarray in self {
let subarrayCount = subarray.count
if offset < subarrayCount {
if length > subarrayCount - offset {
result += subarray[offset...]
length -= subarrayCount - offset
} else {
return result + subarray[offset..<offset + length]
}
}
offset = Swift.max(0, offset - subarrayCount)
}
return nil
}
}
In terms of observations on your code:
I wouldn’t advise
get
method name. It’s not very meaningful name and only conjures up confusion with getters. I’d go with something that captured the “flattening” nature of the routine.As a general rule, we should avoid closures with side-effects in functional programming patterns. Even though you’ve written an “iterative” rendition of the OP’s code, you’re using a functional method,
firstIndex
, and you are updating variables outside the closure. It’s technically allowed but is contrary to the spirit of functional programming patterns and is dependent upon the implementation details offirstIndex
.
answered Apr 2 at 19:00
RobRob
52849
52849
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
add a comment |
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
$begingroup$
FYI, the above is a simple refactoring of the code snippet in the question, but does not attempt to tackle the question of what changes are needed to handle arbitrary depth in the subarrays.
$endgroup$
– Rob
Apr 3 at 8:40
add a comment |
$begingroup$
Extensibility
The following is meant as an addendum to Rob's answer. It is built upon their approach and extends it to work for arrays with arbitrary depth.
extension Array {
func flattened(range: Range<Int>) -> [Any]? {
return helper(range).result?.count == range.upperBound - range.lowerBound ?
helper(range).result :
nil
}
private func helper(_ range: Range<Int>) -> (result: [Any]?, offset: Int) {
var result: [Any] = []
var offset = range.startIndex
let length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for i in self.indices {
let element = self[i]
if let sub_a: [Any] = element as? [Any] {
let tempo = sub_a.helper(offset..<offset + length - result.count)
if let res = tempo.result {
result += res
offset = tempo.offset
} else {
return (result: nil, offset: offset)
}
} else {
if offset == 0 {
result.append(element)
}
offset = Swift.max(0, offset - 1)
}
if result.count == length {
return (result: result, offset: offset)
}
}
return (result: result, offset: offset)
}
}
It has been tested with all of these arrays :
let a: [Any] = [[["0", "1", "2", "3", "4", "5"], ["6", "7"], []],
[["8", "9", "10", "11", "12"], ["13", "14", "15"]]]
let b: [Any] = [[["0", "1"], ["2", "3", "4"]],
[[]],
[["5"], ["6", "7", "8", "9"]],
[["10", "11", "12"], ["13", "14", "15"]]]
let c: [Any] = [["0", "1", "2", "3", "4", "5", ["6", "7", ["8", "9", "10", "11", "12"]]], [], ["13", "14", "15"]]
The output of all three :
print(a.flattened(range: 3..<15))
print(b.flattened(range: 3..<15))
print(c.flattened(range: 3..<15))
is
Optional(["3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"])
$endgroup$
add a comment |
$begingroup$
Extensibility
The following is meant as an addendum to Rob's answer. It is built upon their approach and extends it to work for arrays with arbitrary depth.
extension Array {
func flattened(range: Range<Int>) -> [Any]? {
return helper(range).result?.count == range.upperBound - range.lowerBound ?
helper(range).result :
nil
}
private func helper(_ range: Range<Int>) -> (result: [Any]?, offset: Int) {
var result: [Any] = []
var offset = range.startIndex
let length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for i in self.indices {
let element = self[i]
if let sub_a: [Any] = element as? [Any] {
let tempo = sub_a.helper(offset..<offset + length - result.count)
if let res = tempo.result {
result += res
offset = tempo.offset
} else {
return (result: nil, offset: offset)
}
} else {
if offset == 0 {
result.append(element)
}
offset = Swift.max(0, offset - 1)
}
if result.count == length {
return (result: result, offset: offset)
}
}
return (result: result, offset: offset)
}
}
It has been tested with all of these arrays :
let a: [Any] = [[["0", "1", "2", "3", "4", "5"], ["6", "7"], []],
[["8", "9", "10", "11", "12"], ["13", "14", "15"]]]
let b: [Any] = [[["0", "1"], ["2", "3", "4"]],
[[]],
[["5"], ["6", "7", "8", "9"]],
[["10", "11", "12"], ["13", "14", "15"]]]
let c: [Any] = [["0", "1", "2", "3", "4", "5", ["6", "7", ["8", "9", "10", "11", "12"]]], [], ["13", "14", "15"]]
The output of all three :
print(a.flattened(range: 3..<15))
print(b.flattened(range: 3..<15))
print(c.flattened(range: 3..<15))
is
Optional(["3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"])
$endgroup$
add a comment |
$begingroup$
Extensibility
The following is meant as an addendum to Rob's answer. It is built upon their approach and extends it to work for arrays with arbitrary depth.
extension Array {
func flattened(range: Range<Int>) -> [Any]? {
return helper(range).result?.count == range.upperBound - range.lowerBound ?
helper(range).result :
nil
}
private func helper(_ range: Range<Int>) -> (result: [Any]?, offset: Int) {
var result: [Any] = []
var offset = range.startIndex
let length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for i in self.indices {
let element = self[i]
if let sub_a: [Any] = element as? [Any] {
let tempo = sub_a.helper(offset..<offset + length - result.count)
if let res = tempo.result {
result += res
offset = tempo.offset
} else {
return (result: nil, offset: offset)
}
} else {
if offset == 0 {
result.append(element)
}
offset = Swift.max(0, offset - 1)
}
if result.count == length {
return (result: result, offset: offset)
}
}
return (result: result, offset: offset)
}
}
It has been tested with all of these arrays :
let a: [Any] = [[["0", "1", "2", "3", "4", "5"], ["6", "7"], []],
[["8", "9", "10", "11", "12"], ["13", "14", "15"]]]
let b: [Any] = [[["0", "1"], ["2", "3", "4"]],
[[]],
[["5"], ["6", "7", "8", "9"]],
[["10", "11", "12"], ["13", "14", "15"]]]
let c: [Any] = [["0", "1", "2", "3", "4", "5", ["6", "7", ["8", "9", "10", "11", "12"]]], [], ["13", "14", "15"]]
The output of all three :
print(a.flattened(range: 3..<15))
print(b.flattened(range: 3..<15))
print(c.flattened(range: 3..<15))
is
Optional(["3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"])
$endgroup$
Extensibility
The following is meant as an addendum to Rob's answer. It is built upon their approach and extends it to work for arrays with arbitrary depth.
extension Array {
func flattened(range: Range<Int>) -> [Any]? {
return helper(range).result?.count == range.upperBound - range.lowerBound ?
helper(range).result :
nil
}
private func helper(_ range: Range<Int>) -> (result: [Any]?, offset: Int) {
var result: [Any] = []
var offset = range.startIndex
let length = range.upperBound - range.lowerBound
result.reserveCapacity(length)
for i in self.indices {
let element = self[i]
if let sub_a: [Any] = element as? [Any] {
let tempo = sub_a.helper(offset..<offset + length - result.count)
if let res = tempo.result {
result += res
offset = tempo.offset
} else {
return (result: nil, offset: offset)
}
} else {
if offset == 0 {
result.append(element)
}
offset = Swift.max(0, offset - 1)
}
if result.count == length {
return (result: result, offset: offset)
}
}
return (result: result, offset: offset)
}
}
It has been tested with all of these arrays :
let a: [Any] = [[["0", "1", "2", "3", "4", "5"], ["6", "7"], []],
[["8", "9", "10", "11", "12"], ["13", "14", "15"]]]
let b: [Any] = [[["0", "1"], ["2", "3", "4"]],
[[]],
[["5"], ["6", "7", "8", "9"]],
[["10", "11", "12"], ["13", "14", "15"]]]
let c: [Any] = [["0", "1", "2", "3", "4", "5", ["6", "7", ["8", "9", "10", "11", "12"]]], [], ["13", "14", "15"]]
The output of all three :
print(a.flattened(range: 3..<15))
print(b.flattened(range: 3..<15))
print(c.flattened(range: 3..<15))
is
Optional(["3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14"])
answered Apr 4 at 15:32
ielyamaniielyamani
372213
372213
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216657%2fefficient-way-of-flat-mapping-a-range-of-a-multidimensional-random-access-collec%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown