-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGroupByAverage.py
More file actions
138 lines (123 loc) · 4.4 KB
/
GroupByAverage.py
File metadata and controls
138 lines (123 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import math
from copy import deepcopy
from random import uniform
class Tree:
def __init__(self, startStep):
self.firstStep = TreeNode(startStep)
self.currentStep = self.firstStep
def GetNextStep(self):
"""
calculate all neigbours of this step then find step with minimum score.
if minimum score is lesser than currentStep then return new step with flag true,
otherwise return current step with flag false.
"""
flag = False
minimumScore = self.currentStep.score
neigbureSteps = self.currentStep.CreateNeighbours()
for step in neigbureSteps:
if step.score < minimumScore:
flag = True
minimumScore = step.score
self.currentStep = step
return self.currentStep, flag
class TreeNode:
def __init__(self, groups):
self.groups = groups
self.score = self.CalculateScore()
def CalculateScore(self):
"""
calculate average of each group then calculate their variance as score.
"""
averages = []
for group in self.groups:
sum = 0
for number in group:
sum += number
averages.append(sum / len(group))
sum = 0
minAvg = min(averages)
for avg in averages:
sum += math.pow(avg - minAvg, 2)
variance = sum / (len(averages) - 1)
return variance
def CreateNeighbours(self):
"""
neigboure is a node that by swiping "one number" from a group with "another number" in diffrent group we can creat it using current node.
"""
neigbours = []
for groupIndex in range(len(self.groups)):
for numberIndex in range(len(self.groups[groupIndex])):
for targetGroupIndex in range(groupIndex + 1, len(self.groups)):
for targetNumberIndex in range(len(self.groups[targetGroupIndex])):
neigbours.append(
TreeNode(
self.SwipeNumbers(
deepcopy(self.groups),
numberIndex,
groupIndex,
targetNumberIndex,
targetGroupIndex,
)
)
)
return neigbours
def SwipeNumbers(
self,
groups,
firstNumberIndex,
firstGroupIndex,
secondNumberIndex,
secondGroupIndex,
):
"""
swipe number in firstNumberIndex of firstGroupIndex to number in secondNumberIndex of secondGroupIndex.
"""
temp = groups[firstGroupIndex][firstNumberIndex]
groups[firstGroupIndex][firstNumberIndex] = groups[secondGroupIndex][
secondNumberIndex
]
groups[secondGroupIndex][secondNumberIndex] = temp
return groups
def PrintNode(self):
"""
Print a group in each line.
"""
for group in self.groups:
print(group)
def CreateGroups(groupsCount, numbers):
"""
Divide the "numbers" between "groupsCount" groupes.
"""
numbers = ChangeOrder(numbers)
groups = []
for i in range(groupsCount):
groups.append(numbers[0 : int(len(numbers) / (groupsCount - i))])
numbers = numbers[int(len(numbers) / (groupsCount - i)) :]
return groups
def ChangeOrder(itemsList=[]):
"""
get a list and change order of its items randomly.
"""
for i in range(len(itemsList)):
itemsList.append(itemsList.pop(int(uniform(0, len(itemsList)))))
return itemsList
if __name__ == "__main__":
numbersCount = int(input("How many Numbers?"))
groupsCount = int(input("How many Groups?"))
numbers = list()
inputNumbers = input("input Numbers and devide them with a ' '( space ). ").split(
" "
)
for i in range(numbersCount):
numbers.append(float(inputNumbers[i]))
for i in range(max([numbersCount / 10, 5])):
groups = CreateGroups(groupsCount, numbers)
tree = Tree(groups)
bestResult = tree.currentStep
while True:
step, flag = tree.GetNextStep()
if not flag:
if step.score < bestResult.score:
bestResult = step
break
bestResult.PrintNode()