Swift: How to check intersection with multiple sets? - swift

I have a master set generated by 5 random numbers from 1 to 52; I would like to compare this master set with 13 other sets, each containing 4 numbers between 1 and 52.
Is there a way to check if there are any 2 sets, each containing 2 numbers from the master set?
import UIKit
var firstCard = 0
var secondCard = 0
var thirdCard = 0
var fourthCard = 0
var fifthCard = 0
func generateRandomNumber(_ from:Int, _ to:Int, _ qut:Int?) -> [Int]
{
var myRandomNumbers = [Int]()
var numberOfNumbers = qut
let lower = UInt32(from)
let higher = UInt32(to+1)
if numberOfNumbers == nil || numberOfNumbers! > (to-from) + 1
{
numberOfNumbers = (to-from) + 1
}
while myRandomNumbers.count != numberOfNumbers
{
let myNumber = arc4random_uniform(higher - lower) + lower
if !myRandomNumbers.contains(Int(myNumber))
{
myRandomNumbers.append(Int(myNumber))
}
}
return myRandomNumbers
}
let myArray = generateRandomNumber(1, 53, 5)
firstCard = myArray[0]
secondCard = myArray[1]
thirdCard = myArray[2]
fourthCard = myArray[3]
fifthCard = myArray[4]
let mainSetA = Set([firstCard, secondCard, thirdCard, fourthCard, fifthCard])
let setB: Set = [1, 2, 3, 4]
let setC: Set = [5, 6, 7, 8]
let setD: Set = [9, 10, 11, 12]
let setE: Set = [13, 14, 15, 16]
let setF: Set = [17, 18, 19, 20]
let setG: Set = [21, 22, 23, 24]
let setH: Set = [25, 26, 27, 28]
let setI: Set = [29, 30, 31, 32]
let setJ: Set = [33, 34, 35, 36]
let setK: Set = [37, 38, 39, 40]
let setL: Set = [41, 42, 43, 44]
let setM: Set = [45, 46, 47, 48]
let setN: Set = [49, 50, 51, 52]
no clue what to do next...

Something like this might help:
let mainSet = Set([1, 2, 3, 4])
Here I have three sets out of four that contain at least two items in the main set:
let inputs: [Set<Int>] = [
Set([9, 8, 7, 1]),
Set([9, 8, 1, 2]),
Set([9, 1, 2, 3]),
Set([9, 0, 3, 4])
]
Filter the input sets array, to find any where the intersection between that set and the main set is at least 2:
let matchingSets = inputs.filter {
$0.intersection(mainSet).count >= 2
}

Related

how splitBetween method works

List integerList=[1,2,4,11,14,15,16,16,19,30,31,50,51,100,101,105]; //input
var subList=integerList.splitBetween((v1, v2) => (v2 - v1).abs() > 6);
print(subList); //([1, 2, 4], [11, 14, 15, 16, 16, 19], [30, 31], [50, 51], [100, 101, 105])
what is the logic splitBetween methods works here ?
check each pair of adjacent elements v1 and v2
lets use your data:
[1,2,4,11,14,15,16,16,19,30,31,50,51,100,101,105]
begin with index 0 and 1
we have : v1 = 1 , v2 = 2
then test with the function (v2 - v1).abs() > 6)
( 1-2).abs()>6 = false
index 1 and 2 : v1=2 , v2=4
(2 -4).abs() > 6 = false
index 2 and 3 : v1=4 , v2=11
(4 - 11).abs() > 6 absolute(-7) > 6 = true,
since its true : the elements since the previous chunk-splitting elements are emitted as a list
which means, index 1 - 3 emmited as a list.
current sublist = ([1,2,4])
and so on
index : 4 - 8 is false. and pair of index 8 and 9 is true
current sublist = ([1,2,4], [11,14,15,16,16,19])
repeat untin last index.
lastly :if at last index are false then we keep add to the list. because it says that : Any final elements are emitted at the end.
final result : ([1, 2, 4], [11, 14, 15, 16, 16, 19], [30, 31], [50, 51], [100, 101, 105])

Best way to find the largest amount of consecutive integers in a sorted array in swift, preferably not using a for loop

Given an array of integers for example let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
What is the best way of finding the largest amount of consecutive integers preferably without using a for-in loop. If we would pass this array into a function it would return 3 as '7, 8, 9' is the largest amount of consecutive integers.
let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
func getMaxConsecutives(from array: [Int]) -> Int {
var maxCount = 1
var tempMaxCount = 1
var currentNumber = array[0]
for number in array {
if currentNumber == number - 1 {
tempMaxCount += 1
maxCount = tempMaxCount > maxCount ? tempMaxCount : maxCount
currentNumber = number
} else {
tempMaxCount = 1
currentNumber = number
}
}
return maxCount
}
getMaxConsecutives(from: array)
This works as intended but I would like a more efficient solution something that is not O(n).
I appreciate any creative answers.
You can do it like this:
let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
if let maxCount = IndexSet(array).rangeView.max(by: {$0.count < $1.count})?.count {
print("The largest amount of consecutive integers: \(maxCount)")
//prints 3
}
I think I can write it more tightly (basically as a one-liner):
let array = [1, 3, 4, 7, 8, 9, 12, 14, 15]
let (_,_,result) = array.reduce((-1000,1,0)) {
$1 == $0.0+1 ? ($1,$0.1+1,max($0.2,$0.1+1)) : ($1,1,$0.2)
}
print(result) // 3
But we are still looping through the entire array — so that we are O(n) — and there is no way to avoid that. After all, think about what your eye does as it scans the array looking for the answer: it scans the whole array.
(One way to achieve some savings: You could short-circuit the loop when we are not in the middle of a run and the maximum run so far is longer than what remains of the array! But the gain might not be significant.)

Sub-titles for matrix columns in table

Here's my toy example:
t = table([1,2,3;4,5,6;7,8,9],[10,11,12;13,14,15;16,17,18]);
t.Properties.VariableNames = {'system1', 'system2'};
t.Properties.RowNames = {'obs1', 'obs2', 'obs3'};
I am wondering if it's possible to assign sub titles to the three columns of every variable, such as {'min', 'mean', 'max'}?
You can put those subtitles within the variables using a cell array like this:
t = table({'min', 'mean', 'max'; 1, 2, 3; 4, 5, 6; 7, 8, 9},...
{'min', 'mean', 'max'; 10, 11, 12; 13, 14, 15; 16, 17, 18});
t.Properties.VariableNames = {'system1', 'system2'};
t.Properties.RowNames = {'.','obs1', 'obs2', 'obs3'};
%if you don't like dot (.) as a row name, replace it with char(8203) to have nameless row
which will give:
t =
4×2 table
system1 system2
________________________ ________________________
. 'min' 'mean' 'max' 'min' 'mean' 'max'
obs1 [ 1] [ 2] [ 3] [ 10] [ 11] [ 12]
obs2 [ 4] [ 5] [ 6] [ 13] [ 14] [ 15]
obs3 [ 7] [ 8] [ 9] [ 16] [ 17] [ 18]
If you're looking for functional solution (e.g. t.system1.min) You can nest sub-tables for system1 and system2 with {'min', 'mean', 'max'} as Variable Names. Visually it won't be as useful as other solutions.
dat1 = [1,2,3;4,5,6;7,8,9];
dat2 = [10,11,12;13,14,15;16,17,18];
s1 = table(dat1(:,1),dat1(:,2),dat1(:,3));
s2 = table(dat2(:,1),dat2(:,2),dat2(:,3));
s1.Properties.VariableNames = {'min','mean','max'};
s1.Properties.RowNames = {'obs1', 'obs2', 'obs3'};
s2.Properties.VariableNames = {'min','mean','max'};
s2.Properties.RowNames = {'obs1', 'obs2', 'obs3'};
t = table(s1,s2);
t.Properties.VariableNames = {'system1', 'system2'};
t.Properties.RowNames = {'obs1', 'obs2', 'obs3'};

Check if Data contain another Data using Range in swift 3

I want to check if an instance of Data contain specific data. How to do that using Range in swift 3
Just use range(of:). Example:
let haystack = Data(bytes: [1, 2, 3, 4, 5, 6])
let needle = Data(bytes: [3, 4])
if let range = haystack.range(of: needle) {
print("Found at", range.lowerBound, "..<", range.upperBound)
// Found at 2 ..< 4
}
You an optionally specify a search range and/or search backwards. Example:
let haystack = Data(bytes: [1, 2, 1, 2, 1, 2, 1, 2, 1, 2])
let needle = Data(bytes: [1, 2])
if let range = haystack.range(of: needle, options: .backwards, in: 2..<7) {
print("Found at", range.lowerBound, "..<", range.upperBound)
// Found at 4 ..< 6
}

Find closest longest combination

I have an array with integers [1, 2, 3, 7, 13, 11, 4] and an integer value 12. I need to return an array of a closest combination of sum of the integer values in the new array.
For example: [1, 2, 3, 7, 13, 11, 4] with value 12. The array that need to returned is [1, 2, 3, 4] because the sum of elements 1 + 2 + 3 + 4 <= 12. This is the longest array and prefered over [1, 7, 4] 1 + 7 + 4 = 12.
this solution works if you dont have repeated numbers in array.
var array = [1, 2, 3, 7, 13, 11, 4, -12, 22, 100]
print(array.sorted())
let value = 19
func close(array: [Int], value: Int) -> (Int , Int) {
let sortedArray = array.sorted()
var lastNumberBeforValue = sortedArray.first!
for (index,number) in sortedArray.enumerated() {
let sub = value - number
if sub > 0 {
lastNumberBeforValue = number
}
if sortedArray.contains(sub) && sub != number {
return (sub, number)
} else if index == sortedArray.count - 1 {
if sub < 0 {
let near = close(array: array, value: value - lastNumberBeforValue)
return (near.0, lastNumberBeforValue)
}
let near = close(array: array, value: sub)
return (near.0, number)
}
}
return (-1,-1)
}
let numbers = close(array: array, value: value)
print(numbers) //prints (4, 13)
This solution also finds the two Integers in an array which sum is closest to a given value:
let array = [1, 2, 3, 7, 13, 11, 4]
let value = 5
var difference = Int.max
var result = [Int(), Int()]
for firstInt in array {
for secondInt in array {
let tempDifference = abs((firstInt + secondInt) - value)
if tempDifference < difference {
difference = tempDifference
result[0] = firstInt
result[1] = secondInt
}
}
}
Or a solution that doesn't allow multiple use of the same value:
for (firstIndex, firstInt) in array.enumerated() {
for (secondIndex, secondInt) in array.enumerated() {
guard firstInt != secondInt else { break }
let tempDifference = abs((firstInt + secondInt) - value)
if tempDifference < difference {
difference = tempDifference
result[0] = firstInt
result[1] = secondInt
}
}
}
You can keep on nesting for-loops and guarding for multiple use of same index, if you want longer result arrays. Finally you can take the valid array with the largest result.count. This is not a vary nice solution though, since it computationally heavy, and requires the array to have a static length.
I'm not necessary good with algorithms but I would do it like that :
Since your rule is <= 5 you can sort your array : [1, 2, 3, 7, 13, 11, 4] => [1, 2, 3, 4, 7, 11, 13]
Then, as you don't need integer > 5 you can split your array in 2 parts and take only the first one : [1, 2, 3, 4]
From there you have to add 4 + 3 and match with your value. If it doesn't work do 4 + 2, then 4 + 1. If it's still > 5, loop with 3,2 ; 3,1 ; etc. I did something like this in a Swift way :
// Init
let array = [1, 2, 3, 7, 13, 11, 4]
let value = 5
let sortedArray = array.sorted()
let usefulArray = sortedArray.filter() {$0 < value}
var hasCombination = false
var currentIndex = usefulArray.count - 1
var indexForSum = currentIndex - 1
// Process
if currentIndex > 0 {
hasCombination = true
while usefulArray[currentIndex] + usefulArray[indexForSum] > value {
indexForSum -= 1
if indexForSum < 0 {
currentIndex -= 1
indexForSum = currentIndex - 1
}
if currentIndex == 0 {
hasCombination = false
break
}
}
}
// Result
if hasCombination {
let combination = [usefulArray[indexForSum], usefulArray[currentIndex]]
} else {
print("No combination")
}
I guess it works, tell me if it doesn't !