Project

General

Profile

Download (6.08 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * 
3
 */
4
package eu.etaxonomy.cdm.io.markup;
5

    
6
import java.util.ArrayList;
7
import java.util.Collection;
8
import java.util.HashMap;
9
import java.util.HashSet;
10
import java.util.Iterator;
11
import java.util.List;
12
import java.util.Map;
13
import java.util.Set;
14
import java.util.UUID;
15

    
16
/**
17
 * This class is supposed to find the best sorting order for features (descriptive and other).
18
 * Currently it is not yet very sophisticated.
19
 * 
20
 * @author a.mueller
21
 *
22
 */
23
public class FeatureSorter {
24

    
25
	
26
	class FeatureStatistic{
27

    
28
		private UUID uuid;
29
		boolean isAlwaysHighest = true;
30
		private int before = 0;   //number of features before this feature
31
		private int after = 0;    //number of features after this feature
32
		private int n = 0;      //number of occurrences of this feature
33
		
34
		public FeatureStatistic(UUID uuid) {
35
			this.uuid = uuid;
36
		}
37
		public void addValue(int index, int total) {
38
			if (index != 0){
39
				isAlwaysHighest = false;
40
			}
41
			n++;
42
			before += index;
43
			after += (total - index);
44
		}
45
		@Override
46
		public String toString(){
47
			return uuid != null? uuid.toString(): super.toString();
48
		}
49
		
50
	}
51
	
52
	
53
	/**
54
	 * Compute the order of features.
55
	 * @param orderLists
56
	 * @return
57
	 */
58
	public List<UUID> getSortOrder(Map<String,List<FeatureSorterInfo>> listMap){
59
		List<UUID> result = new ArrayList<UUID>();
60
		//compute highest feature until all lists are empty
61
		removeEmptyLists(listMap);
62
		while (! listMap.isEmpty()){
63
			Map<UUID,FeatureStatistic> statisticMap = computeStatistic(listMap);
64
			FeatureStatistic best = findBest(statisticMap);
65
			result.add(best.uuid);
66
			Map<String, List<FeatureSorterInfo>> subFeatures = removeFromLists(listMap, best.uuid);
67
			List<UUID> subFeatureOrder = getSortOrder(subFeatures);
68
			result.addAll(subFeatureOrder);
69
		}
70
		return result;
71
	}
72

    
73

    
74
	private void removeEmptyLists(Map<String, List<FeatureSorterInfo>> listMap) {
75
		Set<String> keysToRemove = new HashSet<String>();
76
		for(String key : listMap.keySet()){
77
			List<FeatureSorterInfo> list = listMap.get(key);
78
			if (list.isEmpty()){
79
				keysToRemove.add(key);
80
			}
81
		}
82
		for (String key : keysToRemove){
83
			listMap.remove(key);
84
		}
85
		
86
	}
87

    
88

    
89
	/**
90
	 * Removes all entries for given uuid from orderLists and removes empty lists from map.
91
	 * @param orderLists
92
	 * @param uuid
93
	 */
94
	private Map<String, List<FeatureSorterInfo>> removeFromLists(Map<String, List<FeatureSorterInfo>> orderListsMap, UUID uuid) {
95
		Map<String, List<FeatureSorterInfo>> childLists = new HashMap<String, List<FeatureSorterInfo>>();
96
		
97
		Set<String> keySet = orderListsMap.keySet();
98
		Iterator<String> keySetIterator = keySet.iterator();
99
		while (keySetIterator.hasNext()){
100
			String key = keySetIterator.next();
101
			List<FeatureSorterInfo> list = orderListsMap.get(key);			
102
			Iterator<FeatureSorterInfo> it = list.listIterator();
103
			while (it.hasNext()){
104
				FeatureSorterInfo info = it.next();
105
				if (info.getUuid().equals(uuid)){
106
					if (! info.getSubFeatures().isEmpty()){
107
						childLists.put(key, info.getSubFeatures());
108
					}
109
					it.remove();
110
					if (list.isEmpty()){
111
						keySetIterator.remove();
112
					}
113
				}
114
			}
115
		}
116
		return childLists;
117
	}
118

    
119

    
120
	private FeatureStatistic findBest(Map<UUID, FeatureStatistic> statisticMap) {
121
		FeatureStatistic result;
122
		Set<FeatureStatistic> highest = getOnlyHighestFeatures(statisticMap);
123
		if (highest.size() == 1){
124
			result = highest.iterator().next();
125
		}else if (highest.size() > 1){
126
			result = findBestOfHighest(highest);
127
		}else{ //<1
128
			result = findBestOfNonHighest(statisticMap);
129
		}
130
		return result;
131
	}
132

    
133

    
134
	/**
135
	 * If multiple features do all have no higher feature in any list, this method
136
	 * can be called to use an alternative criteria to find the "highest" feature.
137
	 * @param highest
138
	 * @return
139
	 */
140
	private FeatureStatistic findBestOfHighest(Set<FeatureStatistic> highest) {
141
		//current implementation: find the one with the highest "after" value
142
		FeatureStatistic result = highest.iterator().next();
143
		int bestAfter = result.after;
144
		for (FeatureStatistic statistic : highest){
145
			if (statistic.after > bestAfter){
146
				result = statistic;
147
				bestAfter = statistic.after;
148
			}
149
		}
150
		return result;
151
	}
152

    
153

    
154
	/**
155
	 * If no feature is always highest this method can be called to use an alternative criteria
156
	 * to find the "highest" feature. 
157
	 * 
158
	 * @param statisticMap
159
	 * @return
160
	 */
161
	private FeatureStatistic findBestOfNonHighest(Map<UUID, FeatureStatistic> statisticMap) {
162
		//current implementation: find the one with the lowest "before" value
163
		//TODO better use before/n ??
164
		Collection<FeatureStatistic> statistics = statisticMap.values();
165
		FeatureStatistic result = statistics.iterator().next();
166
		int bestBefore = result.before;
167
		for (FeatureStatistic statistic : statistics){
168
			if (statistic.before < bestBefore){
169
				result = statistic;
170
				bestBefore = statistic.before;
171
			}
172
		}
173
		return result;
174
	}
175

    
176

    
177
	private Set<FeatureStatistic> getOnlyHighestFeatures(Map<UUID, FeatureStatistic> statisticMap) {
178
		 Set<FeatureStatistic> result = new HashSet<FeatureStatistic>();
179
		 for (FeatureStatistic statistic : statisticMap.values()){
180
			 if (statistic.isAlwaysHighest){
181
				 result.add(statistic);
182
			 }
183
		 }
184
		 return result;
185
	}
186

    
187

    
188
	private Map<UUID, FeatureStatistic> computeStatistic(Map<String,List<FeatureSorterInfo>> orderLists) {
189
		Map<UUID, FeatureStatistic> result = new HashMap<UUID, FeatureStatistic>();
190
		for (String key :  orderLists.keySet()){
191
			List<FeatureSorterInfo> list = orderLists.get(key);
192
			int n = list.size();
193
			for (FeatureSorterInfo info : list){
194
				FeatureStatistic statistic = getFeatureStatistic(info, result);
195
				int index = list.indexOf(info);
196
				statistic.addValue(index,n);
197
			}
198
		}
199
		return result;
200
	}
201

    
202

    
203
	private FeatureStatistic getFeatureStatistic(FeatureSorterInfo info, Map<UUID, FeatureStatistic> statisticMap) {
204
		UUID uuid = info.getUuid();
205
		FeatureStatistic result = statisticMap.get(uuid);
206
		if (result == null){
207
			result = new FeatureStatistic(uuid);
208
			statisticMap.put(uuid, result);
209
		}
210
		return result;
211
	}
212
}
(1-1/19)