splitting an array into subarrays by variables value - arrays

I have an array of ages.
I want to split the array in to 4 subarrays by the age value.
A -> 0...25
B -> 26...50
c -> 51...75
d -> 76 +
I have no problem iterating through the array and append to different arrays by the age value.
let subArrays: [[Int]] = [[], [], [], []]
for age in ages {
switch age {
case 0...25:
subArrays[0].append(age)
case 26...50:
subArrays[1].append(age)
case 51...75:
subArrays[2].append(age)
default:
subArrays[3].append(age)
}
}
My questions is:
Is there a cleaner way to do this using map, split or any other function.
Thanks

This doesn't use map or anything fancy but you can easily eliminate the switch:
var subArrays: [[Int]] = [[], [], [], []]
for age in ages {
subArrays[min((age - 1) / 25, 3)].append(age)
}
The use of min ensures all values of 76 and greater go into the last slot.
And to test, with all boundary cases, try:
let ages = [ 50, 67, 75, 76, 25, 12, 26, 51, 99, 45, 0, 120, 16 ]
And then:
print(subArrays)
Gives:
[[25, 12, 0, 16], [50, 26, 45], [67, 75, 51], [76, 99, 120]]

A more generic version that does not depend on any mathematical property of your ranges:
func split<T>(array: [T], ranges: [CountableClosedRange<T>]) -> [[T]] {
var result = Array(repeating: [T](), count: ranges.count)
for element in array {
if let subIndex = ranges.index(where: { $0 ~= element }) {
result[subIndex].append(element)
}
}
return result
}
let ages = [10, 20, 30, 40, 50, 60]
let subarrays = split(array: ages, ranges: [0...25, 26...50, 51...75, 76...Int.max])
Note that it does not check for overlapping ranges.

Based on rmaddy's answer (practically the same) but within one line:
let subs = (0...3).map { sub in ages.filter { sub == min(($0 - 1) / 25, 3) } }

Related

How do I add items of multiple arrays with respect to their indexes in dart?

CODE:
void func({String value}) async {
final QuerySnapshot snapshot = await _firestore
.collection('users')
.where("id", isEqualTo: signedInUser.id)
.get();
snapshot.docs.forEach((element) {
List<dynamic> arr = element.data()["array"];
print(arr);
}
}
OUTPUT:
I/flutter (27759): [10, 20, 30, 33, 34, 24]
I/flutter (27759): [2, 42, 45, 23, 85, 51]
I/flutter (27759): [32, 53, 12, 67, 34, 23]
This is what I get when I print the list from Firebase document.
How do I add items of the arrays for each respective indexes? Like; 10 + 2 + 32 for index 0
You should be able to get the List of Lists and then using a for loop sum the data like:
var lists = snapshot.docs.map((e) => e.data()['array']);
var sums = <int>[];
for (int i = 0; i < lists.first.length; i++) {
var sum = 0;
for (var list in lists) {
sum += list[i];
}
sums.add(sum);
}
Be aware that this code is not tested, and you need to make sure that the lists are of equal length or the code might not work as you expect/throw an exception.

Merging multiple arrays and get an array of common elements as output

I'm trying to merge several arrays in javascript/typescript in angular, I need to output an array with the common values in all the arrays.
for eg:
arrayOne = [34, 23, 80, 93, 48]
arrayTwo = [48, 29, 10, 79, 23]
arrayThree = [23, 89, 48, 20, 63]
output: outputArr= [23, 48]
for getting common elements out of 2 arrays i'm filtering one array with the element from the next array.
return this.arrayOne.filter(el => this.arrayTwo.includes(el));
How do I do it effectively if I have to combine large number of arrays....?
Thanks in advance...
You could use multiple Set to quickly look up for each value among the different sets.
const intersection = <T>(arrays: T[][]): T[] => {
if (arrays.length == 0) return [];
if (arrays.length == 1) return arrays[0];
const sets = arrays.slice(1).map(array => new Set(array));
const result = [];
arrays[0].forEach(item => {
if (sets.every(set => set.has(item))) {
result.push(item);
}
});
return result;
};
const arrayOne = [34, 23, 80, 93, 48];
const arrayTwo = [48, 29, 10, 79, 23];
const arrayThree = [23, 89, 48, 20, 63];
const result = intersection([arrayOne, arrayTwo, arrayThree]);
console.log(result);
One approach is to create an initial set that contains the first array's elements. Then loop over the other arrays, converting them to sets and updating the initial set to retain the corresponding set intersection.
const commonElements = function(arrays) {
if (arrays.length == 0)
return [];
const intersection = new Set(arrays[0]);
for (const array of arrays) {
const set = new Set(array);
for (x of intersection) {
if (!set.has(x))
intersection.delete(x);
}
}
return Array.from(intersection);
};
Calling this function on the sample arrays in the question:
commonElements([
[34, 23, 80, 93, 48],
[48, 29, 10, 79, 23],
[23, 89, 48, 20, 63]])
Returns:
[23, 48]

Swift Get x number of elements from an array

I would appreciates some help from someone who knows what they are doing as opposed to me with Arrays in Swift for Xcode.
I have an array of over 40+ heart rate readinsg that I get from an Apple Watch and want to make a new array of only exactly 40 to show on a graph, but they have to be in order, I don't want them to be out of order, so I can't use random or shuffle and get the first 40 or the last 40 of the doubles.
e.g. heartratereadings = [56.0, 57.0, 58.0 ... 101.0]
var fortyReadings = ??heartratereading.somthing to get 40 values in the order they were in?
What is a way I can do that? Thanks in advance ~ Kurt
Thanks you for the solution below I was able to great a cute graph on the watch that shows heart rate readings over time by using 40 instances of a line that is 200px hight. Then I use the individual heart rate to set the heights of each of the 40 bars. Looks great, obviously nt meant for any scientific or medical purpose, just gives me a rough idea of how the heart rate changes over given time. Apples simulator only gives heart rate readings from 58-62 so I can't wait to test. Thank you!!
This is similar to what #staticVoidMan suggested. Instead of recursion, the indices of the new (smaller) array are mapped to indices of the old (larger) array via linear interpolation:
extension Array {
/// Return a smaller array by picking “evenly distributed” elements.
///
/// - Parameter length: The desired array length
/// - Returns: An array with `length` elements from `self`
func pick(length: Int) -> [Element] {
precondition(length >= 0, "length must not be negative")
if length >= count { return self }
let oldMax = Double(count - 1)
let newMax = Double(length - 1)
return (0..<length).map { self[Int((Double($0) * oldMax / newMax).rounded())] }
}
}
Examples:
let doubleArray = [56.0, 57.0, 58.0, 98.0, 101.0, 88.0, 76.0]
print(doubleArray.pick(length: 5))
// [56.0, 58.0, 98.0, 88.0, 76.0]
let intArray = Array(1...10)
print(intArray.pick(length: 8))
// [1, 2, 4, 5, 6, 7, 9, 10]
For starters, this basic extension on Array adds the functionality to return alternate elements from any type of array:
extension Array {
func evenlySpaced(length: Int) -> [Element] {
guard length < self.count else { return self }
let takeIndex = (self.count / length) - 1
let nextArray = Array(self.dropFirst(takeIndex + 1))
return [self[takeIndex]] + nextArray.evenlySpaced(length: length - 1)
}
}
Example 1:
let doubleArray = [56.0, 57.0, 58.0, 98.0, 101.0, 88.0, 76.0]
print(doubleArray.evenlySpaced(length: 5))
[56.0, 57.0, 58.0, 98.0, 101.0, 88.0, 76.0]
evenly spaced would give:
[56.0, 57.0, 58.0, 101.0, 76.0]
Example 2:
let intArray = (1...1000).map { $0 }
print(intArray.evenlySpaced(length: 40))
This shows that if you had an array of 1000 elements, the chosen interval values would be:
[25, 50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 525, 550, 575, 600, 625, 650, 675, 700, 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000]
It's a simple implementation and you could loosely say it's evenly spaced because it tends to favour the initial elements in data sets that are small when compared to the requested length.
Example 3:
let array = (1...10).map { $0 }
print(array.evenlySpaced(length: 8))
[1, 2, 3, 4, 5, 6, 8, 10]
You could instead implement a more balanced logic but the general idea would be the same.
Here is the simplest way to do so:
var heartRateReading = [56.0, 57.0, 58.0, 98.0, ..., 101.0]
//If you want 40 items from the 10th position
var fortySelected = heartRateReading.suffix(from: 10).suffix(40)
// If you want to iterate each second and get 40 values out of it
_ = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (_) in
let values = heartRateReading.suffix(40)
print(values)
}
To get X number of elements from Y index we can have generic function like below:
func fetchElements<T>(sourceArray: [T],
startIndex: Int,
recordCount: Int) -> [T] {
guard startIndex >= 0 && recordCount >= 0 else { return [] }
guard startIndex < sourceArray.count else { return [] }
let arrTrimmedFromStartIndex = Array(sourceArray.suffix(from: startIndex))
let arrWithRequiredCount = Array(arrTrimmedFromStartIndex.prefix(recordCount))
return arrWithRequiredCount
}
Now we can use it with any type as below:
class MyModel {
let name: String
init(name: String) {
self.name = name
}
}
Call to actual function:
let arr = (0..<10).map({ MyModel(name: "\($0)") })
let result = fetchElements(sourceArray: arr,
startIndex: 4,
recordCount: 3)
print(arr.map({$0.name}))
print(result.map({$0.name}))
Print result:
["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
["4", "5", "6"]
Hope this helps!
Just use a for loop
Var forty = [double]()
For n in 1...40 {
forty.insert(heartRate[n], at: 0)
}

How can I sort one array based on another array positions in swift?

In Swift, say I have two arrays:
var array1: [Int] = [100, 40, 10, 50, 30, 20, 90, 70]
var array2: [Int] = [50, 20, 100, 10, 30]
I want to sort my aary1 as per array2
So final output of my array1 will be: // array1 = [50, 20, 100, 10, 30,
40, 90, 70]
Even though your question is quite vaguely worded, judging from your example, what you actually want is the union of the two arrays, with the elements of the smaller array coming in first and after them the unique elements of the bigger array in an unchanged order at the end of this array.
The following code achieves the result of the example:
let combined = array2 + array1.filter{array2.index(of: $0) == nil}
You have not defined how you want the elements in array1 but not in array2 to be sorted. This solution assumes you want to sort those not-found elements by their numeric value:
var array1 = [100, 40, 10, 50, 30, 20, 90, 70]
var array2 = [50, 20, 100, 10, 30]
array1.sort {
let index0 = array2.index(of: $0)
let index1 = array2.index(of: $1)
switch (index0, index1) {
case (nil, nil):
return $0 < $1
case (nil, _):
return false
case (_, nil):
return true
default:
return index0! < index1!
}
}
print(array1) // [50, 20, 100, 10, 30, 40, 70, 90]
// ^ order not defined in array2

Take keys from Dictionary and map them to an array

I'm trying to build a closure that does what my title says. My code runs but it does not print what I expected.
var names: [String] = []
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var ofAge = namesAndAges.filter { namesAndAges in namesAndAges.value > 18 }
var addNames = ofAge.map { ofAge in names.append(ofAge.key) }
print(addNames) //this prints [(), (), ()]
Basically you are misusing filter and map methods.
Try this:
var names: [String] = []
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var ofAge = namesAndAges.filter { $0.value > 18 }
var addNames = ofAge.map { $0.key }
print(addNames) //this prints ["Michael", "Harry", "Tom"]
The issue you're experience is because names.append(ofAge.key) returns Void (a.k.a. the empty tuple, ()). map produces a new Array containing the return values of the given closure after it's been applied to every element of the source array (ofAge, in your example).
The names array will actually contain the data you want, but this isn't how map is meant to be used (you're essentially using it in place of forEach).
Try this instead:
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
var namesOfAge = namesAndAges.filter { $0.value > 18 }.map{ $0.key }
print(namesOfAge)
To avoid looping more than once, this is how I do it:
var namesAndAges = ["Tom": 25, "Michael": 35, "Harry": 28, "Fabien": 16]
let addNames: [String] = namesAndAges.flatMap { $0.value > 18 ? $0.key : nil }
print(addNames) // prints ["Michael", "Harry", "Tom"]
(oh and it's shorter 🙃)

Resources