001package squidpony.squidmath; 002 003import squidpony.ArrayTools; 004 005import java.util.ArrayList; 006import java.util.Collection; 007import java.util.Iterator; 008import java.util.SortedSet; 009 010/** 011 * An ordered bidirectional map-like data structure, with "bundles" of unique E (for Element) keys and unique S (for 012 * Single) keys updated together like a map that can be queried by E key bundles, S keys, or int indices, as well as 013 * like a multimap that can be queried by lone E keys. A bundle can be specified as a Collection of E values, an array 014 * of E values, or in two parts as either of the above given to a BundleBiMap method along with an int array that can 015 * represent variations on E keys (e.g. some quantity for an E value that permits different amounts to be passed with 016 * the unique E values to getS and have it yield a different S for a, say, 1 Foo and 1 Bar vs. 2 Foo and 3 Bar). This 017 * allows an intended purpose for this class as a way to describe crafting recipes that may need various amounts of an 018 * item to be mixed in, and since the quantities are optional, it can still be used to group multiple E keys with S 019 * keys. The multimap property allows you to use an E element key to get all of the S keys that are associated with a 020 * bundle that contains that E key (you can also get the ordering indices for those S keys, which you can use to get the 021 * full bundle if you want). 022 * <br> 023 * Does not implement any interfaces that you would expect for a data structure, because almost every method it has 024 * needs to specify whether it applies to E or S items, or otherwise doesn't fit a normal Collection-like interface's 025 * requirements. 026 * <br> 027 * Closely related to Arrangement, K2, and K2V1 in implementation. 028 * <br> 029 * Created by Tommy Ettinger on 4/26/2017. 030 */ 031public class BundleBiMap<E, S> 032{ 033 private Arrangement<E> elements; 034 private K2<int[][], S> bm; 035 private ArrayList<IntVLA> mm; 036 037 /** 038 * Constructs an empty BundleBiMap. 039 */ 040 public BundleBiMap() 041 { 042 this(Arrangement.DEFAULT_INITIAL_SIZE, Arrangement.DEFAULT_LOAD_FACTOR); 043 } 044 045 /** 046 * Constructs a BundleBiMap with the expected number of indices to hold (the number of bundles and number of S items 047 * is always the same, and this will be more efficient if expected is greater than that number). 048 * @param expected how many bundle-to-single pairings this is expected to hold 049 */ 050 public BundleBiMap(int expected) 051 { 052 this(expected, Arrangement.DEFAULT_LOAD_FACTOR); 053 } 054 055 /** 056 * Constructs a BundleBiMap with the expected number of indices to hold (the number of bundles and number of S items 057 * is always the same, and this will be more efficient if expected is greater than that number) and the load factor 058 * to use, between 0.1f and 0.8f usually (using load factors higher than 0.8f can cause problems). 059 * @param expected the amount of indices (the count of bundles is the same as the count of S items) this should hold 060 * @param f the load factor, probably between 0.1f and 0.8f 061 */ 062 public BundleBiMap(int expected, float f) 063 { 064 elements = new Arrangement<>(expected, f); 065 bm = new K2<>(expected, f, CrossHash.int2DHasher, CrossHash.defaultHasher); 066 mm = new ArrayList<>(expected * 4); 067 } 068 069 070 /** 071 * Constructs a BundleBiMap using another BundleBiMap to copy. 072 * @param other the other BundleBiMap to copy 073 */ 074 public BundleBiMap(BundleBiMap<E, S> other) 075 { 076 if(other == null) 077 { 078 elements = new Arrangement<>(64, 0.75f); 079 bm = new K2<>(16, 0.75f, CrossHash.int2DHasher, CrossHash.defaultHasher); 080 mm = new ArrayList<>(64); 081 } 082 else 083 { 084 elements = new Arrangement<>(other.elements); 085 bm = new K2<>(other.bm); 086 mm = new ArrayList<>(other.mm); 087 } 088 } 089 090 /** 091 * Returns true if this contains the E, element, in any of its bundles of E keys. 092 * @param element the E to check the presence of in all bundles 093 * @return true if element is present in this; false otherwise 094 */ 095 public boolean containsElement(E element) { return elements.containsKey(element); } 096 /** 097 * Returns true if this contains the S, single, in its collection of S items. 098 * @param single the S to check the presence of 099 * @return true if single is present in this; false otherwise 100 */ 101 public boolean containsSingle(S single) { return bm.containsB(single); } 102 103 /** 104 * Returns true if index is between 0 (inclusive) and {@link #size()} (exclusive), or false otherwise. 105 * @param index the index to check 106 * @return true if index is a valid index in the ordering of this BundleBiMap 107 */ 108 public boolean containsIndex(int index) { return index >= 0 && index < bm.size(); } 109 110 /** 111 * Given an int index, finds the associated S key (using index as a point in the ordering). 112 * @param index an int index into this BundleBiMap 113 * @return the S object with index for its position in the ordering, or null if index was invalid 114 */ 115 public S getSingleAt(int index) 116 { 117 return bm.getBAt(index); 118 } 119 120 /** 121 * Gets a random E from this BundleBiMap's individual elements using the given IRNG. 122 * @param random generates a random index to get an E with 123 * @return a randomly chosen E, or null if this is empty 124 */ 125 public E randomElement(IRNG random) 126 { 127 return elements.randomKey(random); 128 } 129 130 /** 131 * Gets a random S from this BundleBiMap using the given IRNG. 132 * @param random generates a random index to get a S with 133 * @return a randomly chosen S, or null if this is empty 134 */ 135 public S randomSingle(IRNG random) 136 { 137 return bm.randomB(random); 138 } 139 140 /** 141 * Changes an existing S key, {@code past}, to another S key, {@code future}, if past exists in this BundleBiMap 142 * and future does not yet exist in this BundleBiMap. This will retain past's point in the ordering for future, so 143 * the associated other key(s) will still be associated in the same way. 144 * @param past a S key, that must exist in this BundleBiMap's S keys, and will be changed 145 * @param future a S key, that cannot currently exist in this BundleBiMap's S keys, but will if this succeeds 146 * @return this for chaining 147 */ 148 public BundleBiMap<E, S> alterB(S past, S future) 149 { 150 bm.alterB(past, future); 151 return this; 152 } 153 154 155 156 /** 157 * Changes the S key at {@code index} to another S key, {@code future}, if index is valid and future does not 158 * yet exist in this K2. The position in the ordering for future will be the same as index, and the same 159 * as the key this replaced, if this succeeds, so the other key(s) at that position will still be associated in 160 * the same way. 161 * @param index a position in the ordering to change; must be at least 0 and less than {@link #size()} 162 * @param future a S key, that cannot currently exist in this BundleBiMap's S keys, but will if this succeeds 163 * @return this for chaining 164 */ 165 public BundleBiMap<E, S> alterSingleAt(int index, S future) 166 { 167 bm.alterBAt(index, future); 168 return this; 169 } 170 /** 171 * Adds a bundle of E keys and a S key at the same point in the ordering (the end) to this BundleBiMap. Neither 172 * parameter can be present in this collection before this is called. 173 * @param e an array of E keys to add; the array cannot already be present, nor can it be null 174 * @param s e S key to add; cannot already be present 175 * @return true if this collection changed as e result of this call 176 */ 177 public boolean put(E[] e, S s) 178 { 179 if(e == null) return false; 180 int len = elements.size; 181 elements.putAll(e); 182 for (int i = len; i < elements.size; i++) { 183 mm.add(new IntVLA(e.length)); 184 } 185 186 elements.putAll(e); 187 int[][] bundle = new int[][]{elements.getArray(e)}; 188 if(!bm.put(bundle, s)) 189 return false; 190 for (int i = 0; i < e.length; i++) { 191 mm.get(bundle[0][i]).add(bm.size()-1); 192 } 193 return true; 194 } 195 /** 196 * Adds a bundle of E keys, mixed with an int array of variations, and a S key at the same point in the ordering 197 * (the end) to this BundleBiMap. Neither the S key nor the bundle (effectively, the pair of e and variation) can be 198 * present in this collection before this is called. 199 * @param e an array of E keys to add; the array cannot already have been inserted with an equivalent variation, nor can it be null 200 * @param variation an int array that can be used to make a different version of e, i.e. the same things at different quantities; cannot be null 201 * @param s e S key to add; cannot already be present 202 * @return true if this collection changed as e result of this call 203 */ 204 public boolean put(E[] e, int[] variation, S s) 205 { 206 if(e == null || variation == null) return false; 207 int len = elements.size; 208 elements.putAll(e); 209 for (int i = len; i < elements.size; i++) { 210 mm.add(new IntVLA(e.length)); 211 } 212 213 int[][] bundle = new int[][]{elements.getArray(e), variation}; 214 if(!bm.put(bundle, s)) 215 return false; 216 for (int i = 0; i < e.length; i++) { 217 mm.get(bundle[0][i]).add(bm.size()-1); 218 } 219 return true; 220 } 221 /** 222 * Adds a bundle of E keys and a S key at the same point in the ordering (the end) to this BundleBiMap. Neither 223 * parameter can be present in this collection before this is called. 224 * @param e an array of E keys to add; the array cannot already be present, nor can it be null 225 * @param s e S key to add; cannot already be present 226 * @return true if this collection changed as e result of this call 227 */ 228 public boolean put(Collection<? extends E> e, S s) 229 { 230 if(e == null) return false; 231 int len = elements.size; 232 elements.putAll(e); 233 for (int i = len; i < elements.size; i++) { 234 mm.add(new IntVLA(e.size())); 235 } 236 int[][] bundle = new int[][]{elements.getArray(e)}; 237 if(!bm.put(bundle, s)) 238 return false; 239 len = bundle[0].length; 240 for (int i = 0; i < len; i++) { 241 mm.get(bundle[0][i]).add(bm.size()-1); 242 } 243 return true; 244 } 245 /** 246 * Adds a bundle of E keys, mixed with an int array of variations, and a S key at the same point in the ordering 247 * (the end) to this BundleBiMap. Neither the S key nor the bundle (effectively, the pair of e and variation) can be 248 * present in this collection before this is called. 249 * @param e an array of E keys to add; the array cannot already have been inserted with an equivalent variation, nor can it be null 250 * @param variation an int array that can be used to make a different version of e, i.e. the same things at different quantities; cannot be null 251 * @param s e S key to add; cannot already be present 252 * @return true if this collection changed as e result of this call 253 */ 254 public boolean put(Collection<? extends E> e, int[] variation, S s) 255 { 256 if(e == null || variation == null) return false; 257 int len = elements.size; 258 elements.putAll(e); 259 for (int i = len; i < elements.size; i++) { 260 mm.add(new IntVLA(e.size())); 261 } 262 int[][] bundle = new int[][]{elements.getArray(e), variation}; 263 if(!bm.put(bundle, s)) 264 return false; 265 len = bundle[0].length; 266 for (int i = 0; i < len; i++) { 267 mm.get(bundle[0][i]).add(bm.size()-1); 268 } 269 return true; 270 } 271 272 /** 273 * Puts all unique E and S keys in {@code aKeys} and {@code bKeys} into this K2 at the end. If an E in aKeys or a S 274 * in bKeys is already present when this would add one, this will not put the E and S keys at that point in the 275 * iteration order, and will place the next unique E and S it finds in the arguments at that position instead. 276 * @param aKeys an Iterable or Collection of E keys to add; should all be unique (like a Set) 277 * @param bKeys an Iterable or Collection of S keys to add; should all be unique (like a Set) 278 * @return true if this collection changed as a result of this call 279 */ 280 public boolean putAll(Iterable<? extends Collection<? extends E>> aKeys, Iterable<? extends S> bKeys) 281 { 282 if(aKeys == null || bKeys == null) return false; 283 Iterator<? extends Collection<? extends E>> aIt = aKeys.iterator(); 284 Iterator<? extends S> bIt = bKeys.iterator(); 285 boolean changed = false; 286 while (aIt.hasNext() && bIt.hasNext()) 287 { 288 changed = put(aIt.next(), bIt.next()) || changed; 289 } 290 return changed; 291 } 292 /** 293 * Puts all unique E and S keys in {@code other} into this K2, respecting other's ordering. If an E or a S in other 294 * is already present when this would add one, this will not put the E and S keys at that point in the iteration 295 * order, and will place the next unique E and S it finds in the arguments at that position instead. 296 * @param other another K2 collection with the same E and S types 297 * @return true if this collection changed as a result of this call 298 */ 299 public boolean putAll(BundleBiMap<? extends E, ? extends S> other) 300 { 301 if(other == null) return false; 302 boolean changed = false; 303 int sz = other.size(); 304 for (int i = 0; i < sz; i++) { 305 int[][] bundle = other.bm.getAAt(i); 306 if(bundle == null || bundle.length == 0) continue; 307 if(bundle.length == 1) 308 changed |= put(elements.keysAt(bundle[0]), other.bm.getBAt(i)); 309 else 310 changed |= put(elements.keysAt(bundle[0]), bundle[1], other.bm.getBAt(i)); 311 } 312 return changed; 313 } 314 315 /** 316 * Given an S key to look up, gets a 2D int array representing the key's matching bundle. The bundle is likely to 317 * use a representation for the first sub-array that will be meaningless without internal information from this 318 * BundleBiMap, but the second sub-array, if present, should match the variation supplied with that bundle 319 * to {@link #put(Object[], int[], Object)} or {@link #put(Collection, int[], Object)}. 320 * <br> 321 * This method copies the 2D int array it returns, so modifying it won't affect the original BundleBiMap. 322 * @param single a S key to look up 323 * @return a copied 2D int array that represents a bundle, or null if single is not present in this 324 */ 325 public int[][] getCode(S single) 326 { 327 if(single == null) return null; 328 return ArrayTools.copy(bm.getAFromB(single)); 329 } 330 /** 331 * Given an index to look up, gets a 2D int array representing the bundle at that index. The bundle is likely to 332 * use a representation for the first sub-array that will be meaningless without internal information from this 333 * BundleBiMap, but the second sub-array, if present, should match the variation supplied with that bundle 334 * to {@link #put(Object[], int[], Object)} or {@link #put(Collection, int[], Object)}. 335 * <br> 336 * This method copies the 2D int array it returns, so modifying it won't affect the original BundleBiMap. 337 * @param index an int index to look up 338 * @return a 2D int array that represents a bundle, or null if index is out of bounds 339 */ 340 public int[][] getCodeAt(int index) 341 { 342 return ArrayTools.copy(bm.getAAt(index)); 343 } 344 /** 345 * Given an index to look up, gets the S key present at that position in the ordering. 346 * @param index an int index to look up 347 * @return a 2D int array that represents a bundle, or null if index is out of bounds 348 */ 349 public S singleAt(int index) 350 { 351 return bm.getBAt(index); 352 } 353 354 /** 355 * Given a bundle of E keys as an array with no variation, gets the matching S key for that bundle, or null if there 356 * is none. 357 * @param e an array of E 358 * @return the S key that corresponds to the given bundle, e 359 */ 360 public S getSingle(E[] e) 361 { 362 if(e == null) return null; 363 return bm.getBFromA(new int[][]{elements.getArray(e)}); 364 } 365 366 /** 367 * Given a bundle of E keys as an array with an int array variation, gets the matching S key for that bundle, or 368 * null if there is none. 369 * @param e an array of E element keys 370 * @param variations an int array that should match an int array used as a variation parameter to put 371 * @return the S key that corresponds to the given bundle, e combined with variations 372 */ 373 public S getSingle(E[] e, int[] variations) 374 { 375 if(e == null || variations == null) return null; 376 return bm.getBFromA(new int[][]{elements.getArray(e), variations}); 377 } 378 379 /** 380 * Given a bundle of E keys as a Collection with no variation, gets the matching S key for that bundle, or 381 * null if there is none. 382 * @param e a Collection of E element keys (each key can be an E or an instance of any subclass of E) 383 * @return the S key that corresponds to the given bundle, e 384 */ 385 public S getSingle(Collection<? extends E> e) 386 { 387 if(e == null) return null; 388 return bm.getBFromA(new int[][]{elements.getArray(e)}); 389 } 390 391 /** 392 * Given a bundle of E keys as a Collection with an int array variation, gets the matching S key for that bundle, or 393 * null if there is none. 394 * @param e a Collection of E element keys (each key can be an E or an instance of any subclass of E) 395 * @param variations an int array that should match an int array used as a variation parameter to put 396 * @return the S key that corresponds to the given bundle, e combined with variations 397 */ 398 public S getSingle(Collection<? extends E> e, int[] variations) 399 { 400 if(e == null || variations == null) return null; 401 return bm.getBFromA(new int[][]{elements.getArray(e), variations}); 402 } 403 /** 404 * Given a bundle as a coded 2D int array, gets the matching S key for that bundle, or null if there is none. 405 * The code parameter should be obtained from one of the methods that specifically returns that kind of 2D array, 406 * since the code uses internal information to efficiently represent a bundle. 407 * @param code a 2D int array representing a bundle that should have been obtained directly from this object 408 * @return the S key that corresponds to the given coded bundle 409 */ 410 public S getSingleCoded(int[][] code) 411 { 412 if(code == null) return null; 413 return bm.getBFromA(code); 414 } 415 416 /** 417 * Gets (in near-constant time) the index of the given S single key in the ordering. 418 * @param single a S single key to look up 419 * @return the position in the ordering of single 420 */ 421 public int indexOfSingle(S single) 422 { 423 return bm.indexOfB(single); 424 } 425 426 /** 427 * Given a coded bundle as produced by some methods in this class, decodes the elements part of the bundle and 428 * returns it as a newly-allocated OrderedSet of E element keys. 429 * @param bundle a coded bundle as a 2D int array 430 * @return an OrderedSet of E element keys corresponding to the data coded into bundle 431 */ 432 public OrderedSet<E> elementsFromCode(int[][] bundle) 433 { 434 if(bundle == null || bundle.length < 1 || bundle[0] == null) return null; 435 return elements.keysAt(bundle[0]); 436 } 437 438 /** 439 * Given a coded bundle as produced by some methods in this class, decodes the variation part of the bundle, if 440 * present, and returns it as a newly-allocated 1D int array. If there is no variation in the given coded bundle, 441 * this returns null. 442 * @param bundle a coded bundle as a 2D int array 443 * @return an OrderedSet of E element keys corresponding to the data coded into bundle 444 */ 445 public int[] variationFromCode(int[][] bundle) 446 { 447 if(bundle == null || bundle.length < 2 || bundle[1] == null) return null; 448 int[] ret = new int[bundle[1].length]; 449 System.arraycopy(bundle[1], 0, ret, 0, ret.length); 450 return ret; 451 } 452 453 /** 454 * Given an S key to look up, gets a (newly-allocated) OrderedSet of E element keys corresponding to that S key. 455 * If a variation is part of the bundle, it will not be present in this, but a copy can be retrieved with 456 * {@link #getBundleVariation(Object)}. 457 * @param single a S key to look up 458 * @return an OrderedSet of the E elements used in the bundle that corresponds to single, or null if invalid 459 */ 460 public OrderedSet<E> getBundleElements(S single) 461 { 462 int[][] bundle; 463 if(single == null || (bundle = bm.getAFromB(single)) == null || bundle.length < 1 || bundle[0] == null) return null; 464 return elements.keysAt(bundle[0]); 465 } 466 467 /** 468 * Given an S key to look up, gets a (newly-allocated) int array that is equivalent to the variation part of the 469 * bundle corresponding to single. If there is no variation in the corresponding bundle, then this returns null. 470 * To get the E elements that are the main part of a bundle, you can use {@link #getBundleElements(Object)}. 471 * @param single a S key to look up 472 * @return an int array copied from the variation part of the bundle that corresponds to single, or null if invalid 473 */ 474 public int[] getBundleVariation(S single) 475 { 476 int[][] bundle; 477 if(single == null || (bundle = bm.getAFromB(single)) == null || bundle.length < 2 || bundle[1] == null) return null; 478 int[] ret = new int[bundle[1].length]; 479 System.arraycopy(bundle[1], 0, ret, 0, ret.length); 480 return ret; 481 } 482 483 /** 484 * Given an index to look up, gets a (newly-allocated) OrderedSet of E element keys in the bundle at that index. 485 * If a variation is part of the bundle, it will not be present in this, but a copy can be retrieved with 486 * {@link #getBundleVariationAt(int)}. 487 * @param index an int position in the ordering to look up 488 * @return an OrderedSet of the E elements used in the bundle present at index, or null if invalid 489 */ 490 public OrderedSet<E> getBundleElementsAt(int index) 491 { 492 int[][] bundle; 493 if((bundle = bm.getAAt(index)) == null || bundle.length < 1) return null; 494 return elements.keysAt(bundle[0]); 495 } 496 /** 497 * Given an index to look up, gets a (newly-allocated) int array that is equivalent to the variation part of the 498 * bundle present at that index. If there is no variation in the corresponding bundle, then this returns null. 499 * To get the E elements that are the main part of a bundle, you can use {@link #getBundleElementsAt(int)}. 500 * @param index an int position in the ordering to look up 501 * @return an int array copied from the variation part of the bundle present at index, or null if invalid 502 */ 503 public int[] getBundleVariationAt(int index) 504 { 505 int[][] bundle; 506 if((bundle = bm.getAAt(index)) == null || bundle.length < 2 || bundle[1] == null) return null; 507 int[] ret = new int[bundle[1].length]; 508 System.arraycopy(bundle[1], 0, ret, 0, ret.length); 509 return ret; 510 } 511 512 /** 513 * Given an E element key that could be used in one or more bundles this uses, finds all S single keys corresponding 514 * to bundles that contain the given element. Thus, if E was String and this BundleBiMap contained ["Copper", "Tin"] 515 * mapped to "Bronze" and ["Zinc", "Copper"] mapped to "Brass", then calling this method with "Copper" would get an 516 * OrderedSet that contains ["Bronze", "Brass"]. 517 * @param element an E element key to look up (probably a component of one or more bundles) 518 * @return an OrderedSet of all S keys where the given element is part of the bundle corresponding to that S key, or null if E does not match anything 519 */ 520 public OrderedSet<S> getManySingles(E element) 521 { 522 if(element == null) return null; 523 int pos; 524 if((pos = elements.getInt(element)) < 0) return null; 525 return bm.keysB.keysAt(mm.get(pos)); 526 } 527 /** 528 * Given an E element key that could be used in one or more bundles this uses, gets all bundles in this object that 529 * contain the given element, as coded 2D int arrays. These coded bundles can be given to 530 * {@link #elementsFromCode(int[][])} and {@link #variationFromCode(int[][])} to get usable information from them. 531 * @param element an E element key to look up (probably a component of one or more bundles) 532 * @return an OrderedSet of all coded 2D int array bundles that contain the given element, or null if E is not in any bundles 533 */ 534 public OrderedSet<int[][]> getManyCoded(E element) 535 { 536 if(element == null) return null; 537 int pos; 538 if((pos = elements.getInt(element)) < 0) return null; 539 return bm.keysA.keysAt(mm.get(pos)); 540 } 541 542 /** 543 * Given an E element key that could be used in one or more bundles this uses, gets all indices in the ordering 544 * that contain a bundle with that element. From such an index, you can use {@link #getSingleAt(int)} to get the 545 * S key at that position, {@link #getBundleElementsAt(int)} to get the E element keys at that position, 546 * {@link #getBundleVariationAt(int)} to get the possible variation at that position, or {@link #getCodeAt(int)} to 547 * get the coded bundle at that position. 548 * @return an OrderedSet of all coded 2D int array bundles that contain the given element, or null if E is not in any bundles 549 */ 550 public int[] getManyIndices(E element) 551 { 552 if(element == null) return null; 553 int pos; 554 if((pos = elements.getInt(element)) < 0) return null; 555 return mm.get(pos).toArray(); 556 } 557 558 /** 559 * Reorders this BundleBiMap using {@code ordering}, which has the same length as this object's {@link #size()} 560 * and can be generated with {@link ArrayTools#range(int)} (which, if applied, would produce no 561 * change to the current ordering), {@link IRNG#randomOrdering(int)} (which gives a random ordering, and if 562 * applied immediately would be the same as calling {@link #shuffle(IRNG)}), or made in some other way. If you 563 * already have an ordering and want to make a different ordering that can undo the change, you can use 564 * {@link ArrayTools#invertOrdering(int[])} called on the original ordering. The effects of this method, if called 565 * with an ordering that has repeat occurrences of an int or contains ints that are larger than its size should 566 * permit, are undefined other than the vague definition of "probably bad, unless you like crashes." 567 * @param ordering an int array or vararg that must contain each int from 0 to {@link #size()} 568 * @return this for chaining 569 */ 570 public BundleBiMap<E, S> reorder(int... ordering) 571 { 572 if(ordering == null || ordering.length != bm.size()) return this; 573 bm.reorder(ordering); 574 int len = mm.size(); 575 for (int i = 0; i < len; i++) { 576 IntVLA iv = mm.get(i); 577 for (int j = 0; j < iv.size; j++) { 578 iv.set(i, ordering[iv.get(i)]); 579 } 580 } 581 return this; 582 } 583 584 /** 585 * Generates a random ordering with rng and applies the same ordering to all kinds of keys this has; they will 586 * maintain their current association to other keys but their ordering/indices will change. 587 * @param rng an IRNG to produce the random ordering this will use 588 * @return this for chaining 589 */ 590 public BundleBiMap<E, S> shuffle(IRNG rng) 591 { 592 return reorder(rng.randomOrdering(bm.size())); 593 } 594 595 /** 596 * Creates a new iterator over the individual E element keys this holds, with a larger total count the iterator may 597 * yield than {@link #size()} in most cases (it should be equal to {@link #elementSize()}), and in no particular 598 * order (though the order should be stable across versions and platforms, no special means are provided to further 599 * control the order). The E keys are individual, not bundled, and duplicate keys should never be encountered even 600 * if an E key appears in many bundles. 601 * @return a newly-created iterator over this BundleBiMap's individual (non-bundled) E keys 602 */ 603 public Iterator<E> iteratorElements() 604 { 605 return elements.iterator(); 606 } 607 /** 608 * Creates a new iterator over the S single keys this holds. The total number of items this yields should be equal 609 * to {@link #size()}. This method can be problematic for garbage collection if called very frequently; it may be 610 * better to access items by index (which also lets you access other keys associated with that index) using 611 * {@link #getSingleAt(int)} in a for(int i=0...) loop. 612 * @return a newly-created iterator over this BundleBiMap's S keys 613 */ 614 public Iterator<S> iteratorSingles() 615 { 616 return bm.iteratorB(); 617 } 618 619 /** 620 * Gets and caches the individual E keys as a Collection that implements SortedSet (and so also implements Set). 621 * @return the E keys as a SortedSet 622 */ 623 public SortedSet<E> getElementSet() { 624 return elements.keySet(); 625 } 626 627 /** 628 * Gets and caches the S single keys as a Collection that implements SortedSet (and so also implements Set). 629 * @return the S keys as a SortedSet 630 */ 631 public SortedSet<S> getSingleSet() { 632 return bm.getSetB(); 633 } 634 635 /** 636 * To be called sparingly, since this allocates a new OrderedSet instead of reusing one. 637 * @return the E keys as an OrderedSet 638 */ 639 public OrderedSet<E> getElementOrderedSet() { 640 return elements.keysAsOrderedSet(); 641 } 642 643 /** 644 * To be called sparingly, since this allocates a new OrderedSet instead of reusing one. 645 * @return the S keys as an OrderedSet 646 */ 647 public OrderedSet<S> getSingleOrderedSet() { 648 return bm.getOrderedSetB(); 649 } 650 651 /** 652 * Gets the total number of bundle-to-single pairs in this BundleBiMap. 653 * @return the total number of bundle keys (equivalently, the number of single keys) in this object 654 */ 655 public int size() { 656 return bm.size(); 657 } 658 659 /** 660 * Gets the total number of unique E element keys across all bundles in this BundleBiMap. Usually not the same as 661 * {@link #size()}, and ordinarily a fair amount larger, though this can also be smaller. 662 * @return the total number of unique E element keys in all bundles this contains 663 */ 664 public int elementSize() { 665 return elements.size(); 666 } 667 668 public boolean isEmpty() 669 { 670 return bm.isEmpty(); 671 } 672 673}