Ignore:
Timestamp:
2016-08-05T20:02:23+02:00 (8 years ago)
Author:
Don-vip
Message:

fix #13271 - Make TagCollection count the occurence of tags (patch by michael2402) - gsoc-core

Location:
trunk/src/org/openstreetmap/josm/data/osm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/TagCollection.java

    r10626 r10736  
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
     6import java.io.Serializable;
    67import java.util.ArrayList;
    78import java.util.Arrays;
     
    1516import java.util.Map;
    1617import java.util.Map.Entry;
     18import java.util.Objects;
    1719import java.util.Set;
    1820import java.util.regex.Pattern;
     21import java.util.stream.Collectors;
     22import java.util.stream.Stream;
    1923
    2024import org.openstreetmap.josm.Main;
     
    4549 * @since 2008
    4650 */
    47 public class TagCollection implements Iterable<Tag> {
     51public class TagCollection implements Iterable<Tag>, Serializable {
     52
     53    private static final long serialVersionUID = 1;
    4854
    4955    /**
     
    146152    }
    147153
    148     private final Set<Tag> tags = new HashSet<>();
     154    private final Map<Tag, Integer> tags = new HashMap<>();
    149155
    150156    /**
     
    163169    public TagCollection(TagCollection other) {
    164170        if (other != null) {
    165             tags.addAll(other.tags);
     171            tags.putAll(other.tags);
    166172        }
    167173    }
     
    200206     */
    201207    public final void add(Tag tag) {
    202         if (tag == null) return;
    203         if (tags.contains(tag)) return;
    204         tags.add(tag);
     208        if (tag != null) {
     209            tags.merge(tag, 1, (i, j) -> i + j);
     210        }
     211    }
     212
     213    /**
     214     * Gets the number of this this tag was added to the collection.
     215     * @param tag The tag
     216     * @return The number of thimes this tag is used in this collection.
     217     * @since 10736
     218     */
     219    public int getTagOccurence(Tag tag) {
     220        return tags.getOrDefault(tag, 0);
    205221    }
    206222
     
    225241     */
    226242    public final void add(TagCollection tags) {
    227         if (tags == null) return;
    228         this.tags.addAll(tags.tags);
     243        if (tags != null) {
     244            for (Entry<Tag, Integer> entry : tags.tags.entrySet()) {
     245                this.tags.merge(entry.getKey(), entry.getValue(), (i, j) -> i + j);
     246            }
     247        }
    229248    }
    230249
     
    247266     */
    248267    public void remove(Collection<Tag> tags) {
    249         if (tags == null) return;
    250         this.tags.removeAll(tags);
     268        if (tags != null) {
     269            tags.stream().forEach(this::remove);
     270        }
    251271    }
    252272
     
    258278     */
    259279    public void remove(TagCollection tags) {
    260         if (tags == null) return;
    261         this.tags.removeAll(tags.tags);
     280        if (tags != null) {
     281            tags.tags.keySet().stream().forEach(this::remove);
     282        }
    262283    }
    263284
     
    269290     */
    270291    public void removeByKey(String key) {
    271         if (key == null) return;
    272         Iterator<Tag> it = tags.iterator();
    273         while (it.hasNext()) {
    274             if (it.next().matchesKey(key)) {
    275                 it.remove();
     292        if (key != null) {
     293            Iterator<Tag> it = tags.keySet().iterator();
     294            while (it.hasNext()) {
     295                if (it.next().matchesKey(key)) {
     296                    it.remove();
     297                }
    276298            }
    277299        }
     
    298320     */
    299321    public boolean contains(Tag tag) {
    300         return tags.contains(tag);
     322        return tags.containsKey(tag);
    301323    }
    302324
     
    306328     * @param key the key to look up
    307329     * @return true if this tag collection contains at least one tag with key <code>key</code>; false, otherwise
    308      */
     330     * @deprecated Use {@link #hasTagsFor(String)} instead.
     331     */
     332    @Deprecated
    309333    public boolean containsKey(String key) {
    310         if (key == null) return false;
    311         for (Tag tag: tags) {
    312             if (tag.matchesKey(key)) return true;
    313         }
    314         return false;
     334        return generateStreamForKey(key).findAny().isPresent();
    315335    }
    316336
     
    324344     */
    325345    public boolean containsAll(Collection<Tag> tags) {
    326         if (tags == null) return false;
    327         return this.tags.containsAll(tags);
     346        if (tags == null) {
     347            return false;
     348        } else {
     349            return this.tags.keySet().containsAll(tags);
     350        }
    328351    }
    329352
     
    336359     */
    337360    public boolean containsAllKeys(Collection<String> keys) {
    338         if (keys == null) return false;
    339         for (String key: keys) {
    340             if (key == null) {
    341                 continue;
    342             }
    343             if (!containsKey(key)) return false;
    344         }
    345         return true;
     361        if (keys == null) {
     362            return false;
     363        } else {
     364            return keys.stream().filter(Objects::nonNull).allMatch(this::hasTagsFor);
     365        }
    346366    }
    347367
     
    350370     *
    351371     * @param key the key to look up
    352      * @return the number of tags with key <code>key</code>. 0, if key is null.
     372     * @return the number of tags with key <code>key</code>, including the empty "" value. 0, if key is null.
    353373     */
    354374    public int getNumTagsFor(String key) {
    355         if (key == null) return 0;
    356         int count = 0;
    357         for (Tag tag: tags) {
    358             if (tag.matchesKey(key)) {
    359                 count++;
    360             }
    361         }
    362         return count;
     375        return (int) generateStreamForKey(key).count();
    363376    }
    364377
     
    381394     */
    382395    public boolean hasValuesFor(String key) {
    383         if (key == null) return false;
    384         Set<String> values = getTagsFor(key).getValues();
    385         values.remove("");
    386         return !values.isEmpty();
     396        return generateStreamForKey(key).filter(t -> !t.getValue().isEmpty()).findAny().isPresent();
    387397    }
    388398
     
    397407     */
    398408    public boolean hasUniqueNonEmptyValue(String key) {
    399         if (key == null) return false;
    400         Set<String> values = getTagsFor(key).getValues();
    401         return values.size() == 1 && !values.contains("");
     409        return generateStreamForKey(key).filter(t -> !t.getValue().isEmpty()).count() == 1;
    402410    }
    403411
     
    410418     */
    411419    public boolean hasEmptyValue(String key) {
    412         if (key == null) return false;
    413         Set<String> values = getTagsFor(key).getValues();
    414         return values.contains("");
     420        return generateStreamForKey(key).anyMatch(t -> t.getValue().isEmpty());
    415421    }
    416422
     
    424430     */
    425431    public boolean hasUniqueEmptyValue(String key) {
    426         if (key == null) return false;
    427         Set<String> values = getTagsFor(key).getValues();
     432        Set<String> values = getValues(key);
    428433        return values.size() == 1 && values.contains("");
    429434    }
     
    439444    public TagCollection getTagsFor(String key) {
    440445        TagCollection ret = new TagCollection();
    441         if (key == null)
    442             return ret;
    443         for (Tag tag: tags) {
    444             if (tag.matchesKey(key)) {
    445                 ret.add(tag);
    446             }
    447         }
     446        generateStreamForKey(key).forEach(ret::add);
    448447        return ret;
    449448    }
     
    475474     */
    476475    public Set<Tag> asSet() {
    477         return new HashSet<>(tags);
     476        return new HashSet<>(tags.keySet());
    478477    }
    479478
     
    482481     * Note that the order of the list is not preserved between method invocations.
    483482     *
    484      * @return the tags of this tag collection as list.
     483     * @return the tags of this tag collection as list. There are no dupplicate values.
    485484     */
    486485    public List<Tag> asList() {
    487         return new ArrayList<>(tags);
     486        return new ArrayList<>(tags.keySet());
    488487    }
    489488
     
    495494    @Override
    496495    public Iterator<Tag> iterator() {
    497         return tags.iterator();
     496        return tags.keySet().iterator();
    498497    }
    499498
     
    504503     */
    505504    public Set<String> getKeys() {
    506         Set<String> ret = new HashSet<>();
    507         for (Tag tag: tags) {
    508             ret.add(tag.getKey());
    509         }
    510         return ret;
     505        return generateKeyStream().collect(Collectors.toCollection(HashSet::new));
    511506    }
    512507
     
    517512     */
    518513    public Set<String> getKeysWithMultipleValues() {
    519         Map<String, Integer> counters = new HashMap<>();
    520         for (Tag tag: tags) {
    521             Integer v = counters.get(tag.getKey());
    522             counters.put(tag.getKey(), (v == null) ? 1 : v+1);
    523         }
    524         Set<String> ret = new HashSet<>();
    525         for (Entry<String, Integer> e : counters.entrySet()) {
    526             if (e.getValue() > 1) {
    527                 ret.add(e.getKey());
    528             }
    529         }
    530         return ret;
     514        HashSet<String> singleKeys = new HashSet<>();
     515        return generateKeyStream().filter(key -> !singleKeys.add(key)).collect(Collectors.toSet());
    531516    }
    532517
     
    562547     */
    563548    public Set<String> getValues() {
    564         Set<String> ret = new HashSet<>();
    565         for (Tag tag: tags) {
    566             ret.add(tag.getValue());
    567         }
    568         return ret;
     549        return tags.keySet().stream().map(e -> e.getValue()).collect(Collectors.toSet());
    569550    }
    570551
     
    578559     */
    579560    public Set<String> getValues(String key) {
    580         Set<String> ret = new HashSet<>();
    581         if (key == null) return ret;
    582         for (Tag tag: tags) {
    583             if (tag.matchesKey(key)) {
    584                 ret.add(tag.getValue());
    585             }
    586         }
    587         return ret;
     561        // null-safe
     562        return generateStreamForKey(key).map(e -> e.getValue()).collect(Collectors.toSet());
    588563    }
    589564
     
    594569     */
    595570    public boolean isApplicableToPrimitive() {
    596         return size() == getKeys().size();
     571        return getKeysWithMultipleValues().isEmpty();
    597572    }
    598573
     
    607582    public void applyTo(Tagged primitive) {
    608583        if (primitive == null) return;
    609         if (!isApplicableToPrimitive())
    610             throw new IllegalStateException(tr("Tag collection cannot be applied to a primitive because there are keys with multiple values."));
    611         for (Tag tag: tags) {
     584        ensureApplicableToPrimitive();
     585        for (Tag tag: tags.keySet()) {
    612586            if (tag.getValue() == null || tag.getValue().isEmpty()) {
    613587                primitive.remove(tag.getKey());
     
    628602    public void applyTo(Collection<? extends Tagged> primitives) {
    629603        if (primitives == null) return;
    630         if (!isApplicableToPrimitive())
    631             throw new IllegalStateException(tr("Tag collection cannot be applied to a primitive because there are keys with multiple values."));
     604        ensureApplicableToPrimitive();
    632605        for (Tagged primitive: primitives) {
    633606            applyTo(primitive);
     
    645618    public void replaceTagsOf(Tagged primitive) {
    646619        if (primitive == null) return;
    647         if (!isApplicableToPrimitive())
    648             throw new IllegalStateException(tr("Tag collection cannot be applied to a primitive because there are keys with multiple values."));
     620        ensureApplicableToPrimitive();
    649621        primitive.removeAll();
    650         for (Tag tag: tags) {
     622        for (Tag tag: tags.keySet()) {
    651623            primitive.put(tag.getKey(), tag.getValue());
    652624        }
     
    663635    public void replaceTagsOf(Collection<? extends Tagged> primitives) {
    664636        if (primitives == null) return;
     637        ensureApplicableToPrimitive();
     638        for (Tagged primitive: primitives) {
     639            replaceTagsOf(primitive);
     640        }
     641    }
     642
     643    private void ensureApplicableToPrimitive() {
    665644        if (!isApplicableToPrimitive())
    666645            throw new IllegalStateException(tr("Tag collection cannot be applied to a primitive because there are keys with multiple values."));
    667         for (Tagged primitive: primitives) {
    668             replaceTagsOf(primitive);
    669         }
    670646    }
    671647
     
    674650     *
    675651     * @param other the other tag collection. If null, replies an empty tag collection.
    676      * @return the intersection of this tag collection and another tag collection
     652     * @return the intersection of this tag collection and another tag collection. All counts are set to 1.
    677653     */
    678654    public TagCollection intersect(TagCollection other) {
    679655        TagCollection ret = new TagCollection();
    680656        if (other != null) {
    681             for (Tag tag: tags) {
    682                 if (other.contains(tag)) {
    683                     ret.add(tag);
    684                 }
    685             }
     657            tags.keySet().stream().filter(other::contains).forEach(ret::add);
    686658        }
    687659        return ret;
     
    706678     *
    707679     * @param other the other tag collection. May be null.
    708      * @return the union of this tag collection and another tag collection
     680     * @return the union of this tag collection and another tag collection. The tag count is summed.
    709681     */
    710682    public TagCollection union(TagCollection other) {
     
    758730
    759731    /**
    760      * Replies the sum of all numeric tag values.
     732     * Replies the sum of all numeric tag values. Ignores dupplicates.
    761733     * @param key the key to look up
    762734     *
    763      * @return the sum of all numeric tag values, as string
     735     * @return the sum of all numeric tag values, as string.
    764736     * @since 7743
    765737     */
     
    776748    }
    777749
     750    private Stream<String> generateKeyStream() {
     751        return tags.keySet().stream().map(tag -> tag.getKey());
     752    }
     753
     754    /**
     755     * Get a stram for the given key.
     756     * @param key The key
     757     * @return The stream. An empty stream if key is <code>null</code>
     758     */
     759    private Stream<Tag> generateStreamForKey(String key) {
     760        return tags.keySet().stream().filter(e -> e.matchesKey(key));
     761    }
     762
    778763    @Override
    779764    public String toString() {
  • trunk/src/org/openstreetmap/josm/data/osm/TagMap.java

    r10680 r10736  
    77import java.util.ArrayList;
    88import java.util.Arrays;
     9import java.util.Collection;
    910import java.util.ConcurrentModificationException;
    1011import java.util.Iterator;
     
    151152    }
    152153
     154    /**
     155     * Creates a new map using the given list of tags. For dupplicate keys the last value found is used.
     156     * @param tags The tags
     157     * @since 10736
     158     */
     159    public TagMap(Collection<Tag> tags) {
     160        for (Tag tag : tags) {
     161            put(tag.getKey(), tag.getValue());
     162        }
     163    }
     164
    153165    @Override
    154166    public Set<Entry<String, String>> entrySet() {
  • trunk/src/org/openstreetmap/josm/data/osm/Tagged.java

    r8510 r10736  
    3535
    3636    /**
     37     * Sets a key/value pairs
     38     *
     39     * @param tag The tag to set.
     40     * @since 10736
     41     */
     42    default void put(Tag tag) {
     43        put(tag.getKey(), tag.getValue());
     44    }
     45
     46    /**
    3747     * Replies the value of the given key; null, if there is no value for this key
    3848     *
Note: See TracChangeset for help on using the changeset viewer.