Recursion function logic friend of friend in a Graph - swift

Hi I have this json file with these partial data, and I will be user 1 in this example, and need to create a graph vertex and connect it to my user for all my friends and then create a vertex and connect my friend friends and so on.
[
{
"id": 1,
"name": "Me",
"friends": [25, 24, 16, 8, 13, 12, 7, 15]
},
{
"id": 2,
"name": "Anne Emerson",
"friends": [3, 21, 4, 20, 24, 5, 7, 12, 18]
},
{
"id": 3,
"name": "Ashley Hopper",
"friends": [2, 22, 10, 20, 25, 11]
},
{
"id": 4,
"name": "Alba Gates",
"friends": [2, 17, 21, 11, 7, 13]
},
{
"id": 5,
"name": "Louise Pennington",
"friends": [2, 23, 22, 15, 20, 24]
},
{
"id": 6,
"name": "Shields Gilliam",
"friends": [26]
},
{
"id": 7,
"name": "Freida Evans",
"friends": [1, 4, 2, 9, 18, 17]
},
{
"id": 8,
"name": "Noel Serrano",
"friends": [1, 24, 18, 9, 16, 11, 23]
}
]
I tried to write a recursion function that goes throw my field list which are users with these ID's [3, 21, 4, 20, 24, 5, 7, 12, 18] like in the example. and create a graph vertex for the User I'm at and connect it with its parent user. and keeps going throw all my friends first then goes throw my friend friends and so on until I discovered all of the friends related to my user weather its directly or indirectly.
Graph methods to use:
create a parent vertex (ME):
let me = graph.createVertex(data: "Me")
connect vertexes together:
graph.add(.undirected, from: me, to: user25, weight: 1)
User model:
struct User: Codable, Identifiable, Hashable {
enum CodingKeys: CodingKey {
case id
case name
case friends
}
var id: Int
var name: String
var friends: [Int]
}
what I tried so far using nested loops:
for (index, i) in friends.enumerated() {
print("i: \(i)")
let getUserByID = datas.users.filter{ $0.id == index}
for (index, i) in getUserByID.enumerated() {
print(i.friends)
}
}
where friends is let friends = [25, 24, 16, 8, 13, 12, 7, 15]
The logic isn't hitting me yet and I wasn't able to achieve this in Swift 5 can anyone help ?
Sample OutPut for my friends mutual list:
John Doe - edge distance: 2, Mutual friends: 5
Bob Kemp - edge Distance: 2, Mutual friends: 3
Bryce Holmes - edge Distance: 3
James Smith - edge Distance: 3
The list should be ranked firstly by edge distance and secondly
by number of mutual friends.

Related

Updating document with mongoose -- one property not being updated?

I have the following code that updates a document in MongoDB:
exercisesRouter.put('/:exerciseId', async (req, res) => {
try {
await mongoose.connect('mongodb+srv://nalanart:password#cluster0.2iplh.mongodb.net/workout-app-db?retryWrites=true&w=majority',
{ useNewUrlParser: true, useUnifiedTopology: true })
await Exercise.findByIdAndUpdate(req.params.exerciseId, {
name: req.body.name,
sessionOne: req.body.sessionOne,
sessionTwo: req.body.sessionTwo,
weight: req.body.weight,
failCount: req.body.failCount,
reps: req.body.reps
})
res.sendStatus(204)
} catch(error) {
throw error
}
})
The problem is that when I use Postman to test it, it updates everything correctly, except the 'reps' property. Here is the JSON body that I put into Postman:
{
"name": "deadlift",
"sessionOne": {
"setsRegular": 4,
"repsRegular": 5,
"setsAmrap": 1,
"repsAmrap": 5
},
"sessionTwo": {
"setsRegular": 0,
"repsRegular": 0,
"setsAmrap": 0,
"repsAmrap": 0
},
"weight": 145,
"failCount": 2,
"reps": [5, 5, 5, 4, 4]
}
This picture shows the document after making the put request (notice reps, which was previously [5, 5, 5, 5, 5] was not updated to [5, 5, 5, 4, 4]
I'm genuinely so confused by this, I feel like it's a small typo in my code that I must have overlooked or possibly something to do with it being an array? Any help is appreciated

I'll be back to edit the question soon so I can ask questions again as this is my only negative question it says I need to improve

I'll be back to edit the question soon so I can ask questions again as this is my only negative question it says I need to improve
You can use Dictionary grouping initializer and map their value count:
let numbers = [
"1, 2, 3, 4",
"5, 6, 7, 8",
"3, 4, 5, 6",
"1, 2, 7, 8",
"1, 2, 3, 4",
"3, 4, 5, 6",
"1, 2, 3, 4"]
let setFrequency = Dictionary(grouping: numbers) { $0 }
.mapValues{ $0.count }
or using reduce(into:)
let setFrequency = numbers.reduce(into: [:]) { $0[$1, default: 0] += 1 }
print(setFrequency) // ["3, 4, 5, 6": 2, "1, 2, 7, 8": 1, "5, 6, 7, 8": 1, "1, 2, 3, 4": 3]

how to print string in a dictionary on swift?

How can I print type of largest number in this dictionary?
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var typeoflargest:String = " "
for (kind, numbers) in interestingNumbers {
for type in kind.characters {
for number in numbers {
if number > largest {
largest = number
typeoflargest = String(type)
}
}
}
}
print(largest)
print(typeoflargest)
output:
25
S
why I got only first character "S" instead of "Square"?
There is no reason to be iterating the characters of the kind string. Just do the following:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
var largest = 0
var typeoflargest:String = ""
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
typeoflargest = kind
}
}
}
print(largest)
print(typeoflargest)
Output:
25
Square
Alternative approach:
let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25],
]
let maximum = interestingNumbers
.map{ type, numbers in return (type: type, number: numbers.max()!) }
.max(by: { $0.number < $1.number })!
print(maximum.type, maximum.number)
Explanation:
First, get the maximal element of each category. Do this by iterating the dictionary, mapping the values from arrays of numbers to maximum numbers (within their respective arrays), yielding:
[
(type: "Square", number: 25), // 25 is the max of [1, 4, 9, 16, 25]
(type: "Prime", number: 13), // 13 is the max of [2, 3, 5, 7, 11, 13]
(type: "Fibonacci", number: 8) // 8 is the max of [1, 1, 2, 3, 5, 8]
]
Then, get the maximal type/number pair, by comparing their numbers, yielding the result:
(type: "Square", number: 25) // 25 is the max of 25, 13, 8

Multiple For Loop condition in Swift

I am working on N-Queens problem and to check whether the queen has been already placed on upper and lower left diagonals, I am finding difficulty in formulating for loop condition.
func isPlaceable(row: Int, column: Int) -> Bool {
// check if one same row another queen exits
for i in 0..<column {
if (solution[row][i] == 1) {
return false
}
}
// check upper left diagonal
// in C or C++ I can do
// for (int i = row, int j = col; i >= 0 && j >= 0; i--, j--) {
// if (board[i][j])
// return false;
//}
}
What would be Swifty way of doing it i.e. Combing the two condition?
One possible solution is you can use zip(_:_:) with two sequence.
func isPlaceable(row: Int, column: Int) -> Bool {
// check if one same row another queen exits
for i in 0..<column {
if (solution[row][i] == 1) {
return false
}
}
// check upper left diagonal
let seq1 = (0...row).reversed()
let seq2 = (0...column).reversed()
for (i,j) in zip(seq1, seq2) {
if (board[i][j]) {
return false
}
}
//your code
}
var i = row
var j = col
while (i >= 0 && j >= 0) {
if (board[i][j])
return false;
i -= 1
j -= 1
}
This type of process benefits a lot from double indirection and prepared matrices.
For example, you could give an identifier to each line segment on the board and check that no two queens use the same line segment.
There are 46 line segments on a standard chess board:
8 vertical
8 horizontal
30 diagonals (15 each)
(I numbered them 1 through 46)
When the queens are properly placed, they will each use 4 line segments (axes) that no other queen uses. Sets are the ideal structure to check for this non intersecting union. By preparing a matrix with a Set of 4 axis identifiers at each row/column, a simple union of the sets for the 8 queens will tell us if they align with each other.
// vertical axes (1...8)
let vAxis = [ [ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ],
[ 1, 2, 3, 4, 5, 6, 7, 8 ]
]
// horizontal axes (9...16)
let hAxis = [ [ 9, 9, 9, 9, 9, 9, 9, 9 ],
[ 10, 10, 10, 10, 10, 10, 10, 10 ],
[ 11, 11, 11, 11, 11, 11, 11, 11 ],
[ 12, 12, 12, 12, 12, 12, 12, 12 ],
[ 13, 13, 13, 13, 13, 13, 13, 13 ],
[ 14, 14, 14, 14, 14, 14, 14, 14 ],
[ 15, 15, 15, 15, 15, 15, 15, 15 ],
[ 16, 16, 16, 16, 16, 16, 16, 16 ],
]
// up right axes (17...31)
let uAxis = [ [ 17, 18, 19, 20, 21, 22, 23, 24 ],
[ 18, 19, 20, 21, 22, 23, 24, 25 ],
[ 19, 20, 21, 22, 23, 24, 25, 26 ],
[ 20, 21, 22, 23, 24, 25, 26, 27 ],
[ 21, 22, 23, 24, 25, 26, 27, 28 ],
[ 22, 23, 24, 25, 26, 27, 28, 29 ],
[ 23, 24, 25, 26, 27, 28, 29, 30 ],
[ 24, 25, 26, 27, 28, 29, 30, 31 ],
]
// down right axes (32...46)
let dAxis = [ [ 39, 40, 41, 42, 43, 44, 45, 46 ],
[ 38, 39, 40, 41, 42, 43, 44, 45 ],
[ 37, 38, 39, 40, 41, 42, 43, 44 ],
[ 36, 37, 38, 39, 40, 41, 42, 43 ],
[ 35, 36, 37, 38, 39, 40, 41, 42 ],
[ 34, 35, 36, 37, 38, 39, 40, 41 ],
[ 33, 34, 35, 36, 37, 38, 39, 40 ],
[ 32, 33, 34, 35, 36, 37, 38, 39 ],
]
// Set of axis numbers for each [row][col] of the board
let axes = (0..<8).map()
{
row in (0..<8).map()
{ Set([ vAxis[row][$0], hAxis[row][$0], uAxis[row][$0], dAxis[row][$0] ]) }
}
// position of each queen ( column number at each row )
var queenCols = [5, 3, 6, 0, 7, 1, 4, 2]
// Check if each queen in queenCols is on its own 4 axes
// We will have 32 (8 x 4) different axes used if no queen aligns with another
let fullCover = queenCols.enumerated()
.reduce(Set<Int>()){ $0.union(axes[$1.0][$1.1]) }
.count == 32
This "fullCover" check can be used in a brute force loop on all 16,777,216 combinations or it can be refined to perform incremental checks in an optimized search tree. (BTW the brute force solution takes only 80 seconds to compute on a MacBook Pro)
So, in the end, you can avoid for loops altogether.
[EDIT] function to find the 92 solutions in a brute force loop:
public func queenPositions() -> [[Int]]
{
var result : [[Int]] = []
let rows : [Int] = Array(0..<8)
for i in 0..<16777216
{
var N:Int = i
let queenCols = rows.map{ _ -> Int in let col = N % 8; N = N / 8; return col}
let fullCover = queenCols.enumerated()
.reduce(Set<Int>()){ $0.union(axes[$1.0][$1.1]) }
.count == 32
if fullCover { result.append(queenCols) }
}
return result
}
[EDIT2] Using the set matrices in an optimized tree search produces the 92 solutions in 0.03 second.
Here is the optimized (and generic) function:
public func queenPositions2(boardSize:Int = 8) -> [[Int]]
{
let vAxis = (0..<boardSize).map{ _ in (0..<boardSize).map{$0} }
let hAxis = (0..<boardSize).map{ Array(repeating:$0+boardSize, count:boardSize) }
let uAxis = (0..<boardSize).map{ row in (0..<boardSize).map{ 2 * boardSize + row + $0} }
let dAxis = (0..<boardSize).map{ row in (0..<boardSize).map{ 5 * boardSize - row + $0} }
let axes = (0..<boardSize).map()
{
row in (0..<boardSize).map()
{ Set([ vAxis[row][$0], hAxis[row][$0], uAxis[row][$0], dAxis[row][$0] ]) }
}
var result : [[Int]] = []
var queenCols : [Int] = Array(repeating:0, count:boardSize)
var colAxes = Array(repeating:Set<Int>(), count:boardSize)
var queenAxes = Set<Int>()
var row = 0
while row >= 0
{
if queenCols[row] < boardSize
{
let newAxes = axes[row][queenCols[row]]
if newAxes.isDisjoint(with: queenAxes)
{
if row == boardSize - 1
{
result.append(queenCols)
queenCols[row] = boardSize
continue
}
else
{
colAxes[row] = newAxes
queenAxes.formUnion(newAxes)
row += 1
queenCols[row] = 0
continue
}
}
}
else
{
row -= 1
if row < 0 { break }
}
queenAxes.subtract(colAxes[row])
colAxes[row] = Set<Int>()
queenCols[row] += 1
}
return result
}
Given a 10x10 board, the 724 solutions are generated in 0.11 second.
[EDIT3] one liner "for loop" ...
You can generate an array of (row,column) coordinate for the 4 axes of a given position and use that as your data in the for loop:
func isPlaceable(row: Int, column: Int) -> Bool
{
var coverage = (0..<8).map{($0,column)} // horizontal
coverage += (0..<8).map{(row,$0)} // vertical
coverage += zip((max(0,row-column)..<8),(max(0,column-row)..<8)) // diagonal down
coverage += zip((0...min(7,row+column)).reversed(),(max(0,column+row-7)..<8)) // diagonal up
// return !coverage.contains{solution[$0][$1] == 1}
for (r,c) in coverage
{
if solution[r][c] == 1 { return false }
}
return true
}
It feels wasteful to rebuild the whole coverage list every time though. I would compute it once for every coordinate and place it in a row/column matrix for reuse in the isPlaceable() function.

Update Elements in Array

Lets say I have this Object:
{town_id: 13, houses_data: [
{house_id: 5, price: 32, description: "thats a house"},
{house_id: 2, price: 12, description: "thats a house"}
]
}
And I want to update the desription of house with id 5 to "sold":
{town_id: 13, houses_data: [
{house_id: 5, price: 32, description: "sold"},
{house_id: 2, price: 12, description: "thats a house"}
]
}
What I tried:
town1 = town.findOne({town_id: 13});
Get the houses_data:
twon1.houses_data
And tried to update only the house_data where id = 5
twon1.houses_data.find({house_id: 5}).update(description: "sold");
But I get this error message:
[object Object],[object Object] has no method 'find'
What do I wrong? Thanks
You might use $ to update the first embedded document matching the given query:
db.test.town.update({town_id: 13, "houses_data.house_id":5},
{$set: { "houses_data.$.description": "sold"}})