1

Supposing I have this TreeSet<Integer>:

1 3 4 6 8 9 10

And I want the top-k "closest" elements to an input number x.

For example, with k=3 and x=5 I want to get:

4 6 3

Is there any way to do this?

justHelloWorld
  • 6,478
  • 8
  • 58
  • 138
  • 1
    "Is there any way to do this?" Yes. Write a method to do so. If you mean "Is there a method in TreeSet that does this?", the answer is no. – lucasvw Jun 13 '17 at 15:05
  • Also, if you plan to implement this yourself (which you probably will have to), you'll need to define certain cases. What happens if `k` is greater than the size of the set? What happens if `x` is not in the set? What happens if two elements are tied for closest? – lucasvw Jun 13 '17 at 15:10

2 Answers2

4

It seems what you need to do is to get a headSet with all elements smaller than the target element and a tailSet for the bigger elements. Now the algorithm will be somewhat similar to merge phase of merge sort.

  • Take a descendingIterator of the headSet and an iterator over the tail set. Call these c_desc, and c_asc
  • Check which of the two elements is closer to the target value x. Take this value and advance the iterator
  • Take care for when one of the iterators is at the end of the corresponding set view
  • Continue doing that until you have taken k elements
Ivaylo Strandjev
  • 69,226
  • 18
  • 123
  • 176
  • Don't do work for OP. How will OP learn if you do all the lifting for them? – lucasvw Jun 13 '17 at 15:12
  • 2
    I have not done any work for the OP, only pointed to the appropriate functions. It is still up to OP to turn this into actual implementation by researching the relevant documentation that I have pointed to. – Ivaylo Strandjev Jun 13 '17 at 15:14
  • I suppose. IMHO what you've given is essentially pseudo-code, which is relatively easy to turn into actual code. – lucasvw Jun 13 '17 at 15:18
  • 1
    @lucasvw Giving pointers is totally accepted. Heck, you even give some in your second comment of the question! "Do as I say, not as I do"? – Olivier Grégoire Jun 13 '17 at 15:32
  • 2
    This seems like a reasonable amount of detail for a homework question. See [How do I ask and answer homework questions](https://meta.stackoverflow.com/questions/334822): *"You can use pseudo-code first...".* – Andy Thomas Jun 13 '17 at 15:45
  • @OlivierGrégoire There's a big difference between pointing out potential problems (my second comment), and providing a lot of the work that needs to be done (this answer). – lucasvw Jun 13 '17 at 15:45
  • @OlivierGrégoire I would also point out that OP did practically nothing to attempt to solve this first, which is a guideline to asking homework questions in the link provided by Andy Thomas – lucasvw Jun 13 '17 at 15:47
  • 1
    So what? Act appropriately and flag the question and don't berate answerers. – Olivier Grégoire Jun 13 '17 at 15:52
  • 1
    @OlivierGrégoire I don't believe I've berated anyone, but I will gladly apologize if I have. I merely expressed my opinion. – lucasvw Jun 13 '17 at 15:54
2

By "closest to x" I assume you mean the lowest values of abs(n - x).

That is, for x=5, k=3:

1,3,4,6,8,9,10   -> 3,4,6
3,4,5,10,11,12   -> 3,4,5
0,1,2,5,6,7,8    -> 5,6,7

If that's the case, I would:

  • map each Integer to a Pair<Integer,Integer>
    • n -> new Pair(n, abs(n - x)) so one value is n, the other is its distance from x.
    • (write your own Pair, (ab)use Map.Entry, (ab)use Integer[2] or find one in a library)
  • sort the list of Pair<> using a comparator that uses the distance
  • take the first k elements from that sorted list.

Using Java 8 streams:

 set.stream()
   .map( n -> new Pair(n, Math.abs(x - n)))
   .sorted(Comparator.comparing( p -> p.right())
   .limit(k)
   .map( p -> p.left())
   .collect(Collectors.toSet());
slim
  • 40,215
  • 13
  • 94
  • 127
  • See: https://stackoverflow.com/questions/156275/what-is-the-equivalent-of-the-c-pairl-r-in-java – slim Jun 13 '17 at 16:02