optaplanner can't get the best solution, and different input orders produce different solutions - optaplanner

I'm trying to make a demo using optaplanner: there are some schemes, each scheme has attribute of gain and cost, and a scheme may conflict with one or more other schemes. The question is to find out a group of schemes which match following constraints:
hard constraint: selected schemea may not conflict with each other in this group
soft constraint: make the difference between total gain and total cost as high as possible
I built following code and try to resolve the question:
#PlanningEntity
#Data
#NoArgsConstructor
public class Scheme {
#PlanningId
private String id;
private int gain;
private int cost;
#PlanningVariable(valueRangeProviderRefs = {"validRange"})
// when valid is ture means this scheme will be selected into the solution group
private Boolean valid;
private Set<String> conflicts = new HashSet<>();
public void addConflict(String id) {
conflicts.add(id);
}
public Scheme(String id, int gain, int cost, String[] conflicts) {
this.id = id;
this.gain = gain;
this.cost = cost;
for (String s : conflicts) {
addConflict(s);
}
}
}
#PlanningSolution
public class SchemeSolution {
private HardSoftScore score;
private List<Scheme> schemeList;
#ProblemFactCollectionProperty
#ValueRangeProvider(id = "validRange")
public List<Boolean> getValidRange() {
return Arrays.asList(Boolean.FALSE, Boolean.TRUE);
}
#PlanningScore
public HardSoftScore getScore() {
return score;
}
public void setScore(HardSoftScore score) {
this.score = score;
}
#PlanningEntityCollectionProperty
public List<Scheme> getSchemeList() {
return schemeList;
}
public void setSchemeList(List<Scheme> schemeList) {
this.schemeList = schemeList;
}
}
And the constraint rule as below:
rule "conflictCheck"
when
Boolean(this==true) from accumulate (
$schs: List() from collect (Scheme(valid==true)),
init(boolean cfl = false;Set cfSet = new HashSet();List ids = new ArrayList()),
action(
for(int i = 0; i < $schs.size(); ++i) {
Scheme sch = (Scheme)$schs.get(i);
cfSet.addAll(sch.getConflicts());
ids.add(sch.getId());
}
for( int i = 0; i < ids.size(); ++i) {
String id = (String)ids.get(i);
if(cfSet.contains(id)) {
cfl = true;
return true;
}
}
),
result(cfl)
)
then
scoreHolder.addHardConstraintMatch(kcontext, -10000);
end
rule "bestGain"
when
$gc : Number() from
accumulate(
Scheme(valid==true, $gain : gain, $cost: cost),
sum($gain - $cost)
)
then
scoreHolder.addSoftConstraintMatch(kcontext, $gc.intValue());
end
Then I constructed three schemes as input of the test. Oddly, I found that optaplanner can't get the best solution, and different input orders produce different solutions.
When I set input as following:
private static List<Scheme> getSchemes() {
List<Scheme> ret = new ArrayList();
ret.add(new Scheme("S1", 5, 2, new String[]{"S3"}));
ret.add(new Scheme("S2", 3, 1, new String[]{"S3"}));
ret.add(new Scheme("S3", 10, 4, new String[]{"S1", "S2"}));
return ret;
}
the output is :
0hard/5soft
Scheme(id=S1, gain=5, cost=2, valid=true, conflicts=[S3])
Scheme(id=S2, gain=3, cost=1, valid=true, conflicts=[S3])
Scheme(id=S3, gain=10, cost=4, valid=false, conflicts=[S1, S2])
And when I set input as following:
private static List<Scheme> getSchemes() {
List<Scheme> ret = new ArrayList();
ret.add(new Scheme("S3", 10, 4, new String[]{"S1", "S2"}));
ret.add(new Scheme("S1", 5, 2, new String[]{"S3"}));
ret.add(new Scheme("S2", 3, 1, new String[]{"S3"}));
return ret;
}
I get the best solution and the output is :
0hard/6soft
Scheme(id=S3, gain=10, cost=4, valid=true, conflicts=[S1, S2])
Scheme(id=S1, gain=5, cost=2, valid=false, conflicts=[S3])
Scheme(id=S2, gain=3, cost=1, valid=false, conflicts=[S3])
Could anyone help me about it?

Related

Optimizing Transposing and Comparison of Concurrent List in Java 8

I have an application in Java 8 Collecting Data of multiple Threads using BlockingQueue.
I need to perform comparison of samples.
But my application is very large, I implemented a mock application (Github) in Java 8.
I'm generating a chunk of bytes (really is random order).
The bytes are stored into ChunkDTO class.
I implemented a capturer the ChunkDTO in a List, code in Capturer class.
Each ChunkDTO of List is translated into a List of Samples (TimePitchValue exactly) returning a nested List (or List of List of TimePitchValue).
Later the nested List is transposed in order to performs comparisons between TimePitchValue with the same time value.
Due to enormous volume of TimePitchValue instances it's consumes huge time in my application.
Here some code (The complete functional Code is in Github) because is still large for this site).
public class Generator {
final static Logger LOGGER = Logger.getLogger("SampleComparator");
public static void main(String[] args) {
long previous = System.nanoTime();
final int minBufferSize = 2048;
int sampleRate = 8192;
int numChannels = 1;
int numBytesPerSample = 1;
int samplesChunkPerSecond = sampleRate / minBufferSize;
int minutes = 0;
int seconds = 10;
int time = 60 * minutes + seconds;
int chunksBySecond = samplesChunkPerSecond * numBytesPerSample * numChannels;
int pitchs = 32;
boolean signed = false;
boolean endianness = false;
AudioFormat audioformat = new AudioFormat(sampleRate, 8 * numBytesPerSample, numChannels, signed, endianness);
ControlDSP controlDSP = new ControlDSP(audioformat);
BlockingQueue<ChunkDTO> generatorBlockingQueue = new LinkedBlockingQueue<>();
Capturer capturer = new Capturer(controlDSP, pitchs, pitchs * time * chunksBySecond, generatorBlockingQueue);
controlDSP.getListFuture().add(controlDSP.getExecutorService().submit(capturer));
for (int i = 0; i < time * chunksBySecond; i++) {
for (int p = 0; p < pitchs; p++) {
ChunkDTO chunkDTO = new ChunkDTO(UtilClass.getArrayByte(minBufferSize), i, p);
LOGGER.info(String.format("chunkDTO: %s", chunkDTO));
try {
generatorBlockingQueue.put(chunkDTO);
} catch (InterruptedException ex) {
LOGGER.info(ex.getMessage());
}
}
try {
Thread.sleep(1000 / chunksBySecond);
} catch (Exception ex) {
}
}
controlDSP.tryFinishThreads(Thread.currentThread());
long current = System.nanoTime();
long interval = TimeUnit.NANOSECONDS.toSeconds(current - previous);
System.out.println("Seconds Interval: " + interval);
}
}
Capturer Class
public class Capturer implements Callable<Void> {
private final ControlDSP controlDSP;
private final int pitchs;
private final int totalChunks;
private final BlockingQueue<ChunkDTO> capturerBlockingQueue;
private final Counter intCounter;
private final Map<Long, List<ChunkDTO>> mapIndexListChunkDTO = Collections.synchronizedMap(new HashMap<>());
private volatile boolean isRunning = false;
private final String threadName;
private static final Logger LOGGER = Logger.getLogger("SampleComparator");
public Capturer(ControlDSP controlDSP, int pitchs, int totalChunks, BlockingQueue<ChunkDTO> capturerBlockingQueue) {
this.controlDSP = controlDSP;
this.pitchs = pitchs;
this.totalChunks = totalChunks;
this.capturerBlockingQueue = capturerBlockingQueue;
this.intCounter = new Counter();
this.controlDSP.getListFuture().add(this.controlDSP.getExecutorService().submit(() -> {
while (intCounter.getValue() < totalChunks) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
capturerBlockingQueue.add(new ChunkDTOStopper());
}));
this.threadName = this.getClass().getSimpleName();
}
#Override
public Void call() throws Exception {
long quantity = 0;
isRunning = true;
while (isRunning) {
try {
ChunkDTO chunkDTO = capturerBlockingQueue.take();
if (chunkDTO instanceof ChunkDTOStopper) {
break;
}
//Find or Create List (according to Index) to add the incoming Chunk
long index = chunkDTO.getIndex();
int sizeChunk = chunkDTO.getChunk().length;
List<ChunkDTO> listChunkDTOWithIndex = getListChunkDTOByIndex(chunkDTO);
//When the List (according to Index) is completed and processed
if (listChunkDTOWithIndex.size() == pitchs) {
mapIndexListChunkDTO.remove(index);
TransposerComparator transposerComparator = new TransposerComparator(controlDSP, controlDSP.getAudioformat(), index, sizeChunk, listChunkDTOWithIndex);
controlDSP.getListFuture().add(controlDSP.getExecutorService().submit(transposerComparator));
}
quantity++;
intCounter.setValue(quantity);
LOGGER.info(String.format("%s\tConsumes:%s\ttotal:%05d", threadName, chunkDTO, quantity));
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
LOGGER.info(String.format("%s\tReceived:%05d\tQty:%s\tPitchs:%s\tEND\n", threadName, quantity, quantity / pitchs, pitchs));
return null;
}
private List<ChunkDTO> getListChunkDTOByIndex(ChunkDTO chunkDTO) {
List<ChunkDTO> listChunkDTOWithIndex = mapIndexListChunkDTO.get(chunkDTO.getIndex());
if (listChunkDTOWithIndex == null) {
listChunkDTOWithIndex = new ArrayList<>();
mapIndexListChunkDTO.put(chunkDTO.getIndex(), listChunkDTOWithIndex);
listChunkDTOWithIndex = mapIndexListChunkDTO.get(chunkDTO.getIndex());
}
listChunkDTOWithIndex.add(chunkDTO);
return listChunkDTOWithIndex;
}
}
TransposerComparator class.
The optimization required is in this code, specifically on transposedNestedList method.
public class TransposerComparator implements Callable<Void> {
private final ControlDSP controlDSP;
private final AudioFormat audioformat;
private final long index;
private final int sizeChunk;
private final List<ChunkDTO> listChunkDTOWithIndex;
private final String threadName;
private static final Logger LOGGER = Logger.getLogger("SampleComparator");
public TransposerComparator(ControlDSP controlDSP, AudioFormat audioformat, long index, int sizeChunk, List<ChunkDTO> listChunkDTOWithIndex) {
this.controlDSP = controlDSP;
this.audioformat = audioformat;
this.index = index;
this.sizeChunk = sizeChunk;
this.listChunkDTOWithIndex = listChunkDTOWithIndex;
this.threadName = this.getClass().getSimpleName() + "_" + String.format("%05d", index);
}
#Override
public Void call() throws Exception {
Thread.currentThread().setName(threadName);
LOGGER.info(String.format("%s\tINI", threadName));
try {
int numBytesPerSample = audioformat.getSampleSizeInBits() / 8;
int quantitySamples = sizeChunk / numBytesPerSample;
long baseTime = quantitySamples * index;
// Convert the List of Chunk Bytes to Nested List of TimePitchValue
List<List<TimePitchValue>> nestedListTimePitchValue = listChunkDTOWithIndex
.stream()
.map(chunkDTO -> {
return IntStream
.range(0, quantitySamples)
.mapToObj(time -> {
int value = extractValue(chunkDTO.getChunk(), numBytesPerSample, time);
return new TimePitchValue(chunkDTO.getPitch(), baseTime + time, value);
}).collect(Collectors.toList());
}).collect(Collectors.toList());
List<List<TimePitchValue>> timeNestedListTimePitchValue = transposedNestedList(nestedListTimePitchValue);
} catch (Exception ex) {
ex.printStackTrace();
LOGGER.log(Level.SEVERE, null, ex);
throw ex;
}
return null;
}
private static int extractValue(byte[] bytesSamples, int numBytesPerSample, int time) {
byte[] bytesSingleNumber = Arrays.copyOfRange(bytesSamples, time * numBytesPerSample, (time + 1) * numBytesPerSample);
int value = numBytesPerSample == 2
? (UtilClass.Byte2IntLit(bytesSingleNumber[0], bytesSingleNumber[1]))
: (UtilClass.byte2intSmpl(bytesSingleNumber[0]));
return value;
}
private static List<List<TimePitchValue>> transposedNestedList(List<List<TimePitchValue>> nestedList) {
List<List<TimePitchValue>> outNestedList = new ArrayList<>();
nestedList.forEach(pitchList -> {
pitchList.forEach(pitchValue -> {
List<TimePitchValue> listTimePitchValueWithTime = listTimePitchValueWithTime(outNestedList, pitchValue.getTime());
if (!outNestedList.contains(listTimePitchValueWithTime)) {
outNestedList.add(listTimePitchValueWithTime);
}
listTimePitchValueWithTime.add(pitchValue);
});
});
outNestedList.forEach(pitchList -> {
pitchList.sort(Comparator.comparingInt(TimePitchValue::getValue).reversed());
});
return outNestedList;
}
private static List<TimePitchValue> listTimePitchValueWithTime(List<List<TimePitchValue>> nestedList, long time) {
List<TimePitchValue> listTimePitchValueWithTime = nestedList
.stream()
.filter(innerList -> innerList.stream()
.anyMatch(timePitchValue -> timePitchValue.getTime() == time))
.findAny()
.orElseGet(ArrayList::new);
return listTimePitchValueWithTime;
}
}
I was testing:
With 5 Seconds in Generator class and the List<List<TimePitchValue>> timeNestedListTimePitchValue = transposedNestedList(nestedListTimePitchValue); line in TransposerComparator class, Commented 7 Seconds needed, Uncommented 211 Seconds needed.
With 10 Seconds in Generator class and the List<List<TimePitchValue>> timeNestedListTimePitchValue = transposedNestedList(nestedListTimePitchValue); line in TransposerComparator class, Commented 12 Seconds needed, Uncommented 574 Seconds needed.
I need to use the application at least 60 minutes.
With the purpose of reduce the needed (consumed) time, I have two ways:
I choose for short is to optimize the methods that I am currently using.
That should be successful but longer and is to use GPGPU, but I don't know where to start implementing it yet.
QUESTIONS
This Question is for the first way: What changes do you recommend in the code of the transposedNestedList method in order to improve speed?
Is there better alternative to use this Comparison?
outNestedList.forEach(pitchList -> {
pitchList.sort(Comparator.comparingInt(TimePitchValue::getValue).reversed());
});

OptaPlaner simple example cant find feasible solution

to get familiar with optaplanner i created a simple test project. I only have one Solution and one Entity class. The Entity has only one value between 0 and 9. There should only be odd numbers and the sum of all should be less then 10 (this are just some random constraints i came up with).
As Score i use a simple HardSoftScore. Here is the code:
public class TestScoreCalculator implements EasyScoreCalculator<TestSolution>{
#Override
public HardSoftScore calculateScore(TestSolution sol) {
int hardScore = 0;
int softScore = 0;
int valueSum = 0;
for (TestEntity entity : sol.getTestEntities()) {
valueSum += entity.getValue() == null? 0 : entity.getValue();
}
// hard Score
for (TestEntity entity : sol.getTestEntities()) {
if(entity.getValue() == null || entity.getValue() % 2 == 0)
hardScore -= 1; // constraint: only odd numbers
}
if(valueSum > 10)
hardScore -= 2; // constraint: sum should be less than 11
// soft Score
softScore = valueSum; // maximize
return HardSoftScore.valueOf(hardScore, softScore);
}
}
and this is my config file:
<?xml version="1.0" encoding="UTF-8"?>
<solver>
<!-- Domain model configuration -->
<scanAnnotatedClasses/>
<!-- Score configuration -->
<scoreDirectorFactory>
<easyScoreCalculatorClass>score.TestScoreCalculator</easyScoreCalculatorClass>
</scoreDirectorFactory>
<!-- Optimization algorithms configuration -->
<termination>
<secondsSpentLimit>30</secondsSpentLimit>
</termination>
</solver>
for some reason OptaPlanner cant find a feasible solution. It terminates with LS step (161217), time spent (29910), score (-2hard/10soft), best score (-2hard/10soft)... and the solution 9 1 0 0.
So the hardScore is -2 because the two 0 are not odd. A possible solution would be 7 1 1 1 for example. Why is this ? This should be a really easy example ...
(when i set the Start values to 7 1 1 1 it terminates with this solution and a score of (0hard/10soft) how it should be)
Edit:
The Entity class
#PlanningEntity
public class TestEntity {
private Integer value;
#PlanningVariable(valueRangeProviderRefs = {"TestEntityValueRange"})
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
#ValueRangeProvider(id = "TestEntityValueRange")
public CountableValueRange<Integer> getStartPeriodRange() {
return ValueRangeFactory.createIntValueRange(0, 10);
}
}
The Solution class
#PlanningSolution
public class TestSolution {
private List<TestEntity> TestEntities;
private HardSoftScore score;
#PlanningEntityCollectionProperty
public List<TestEntity> getTestEntities() {
return TestEntities;
}
public void setTestEntities(List<TestEntity> testEntities) {
TestEntities = testEntities;
}
#PlanningScore
public HardSoftScore getScore() {
return score;
}
public void setScore(HardSoftScore score) {
this.score = score;
}
#Override
public String toString() {
String str = "";
for (TestEntity testEntity : TestEntities)
str += testEntity.getValue()+" ";
return str;
}
}
The Main Program class
public class Main {
public static final String SOLVER_CONFIG = "score/TestConfig.xml";
public static int printCount = 0;
public static void main(String[] args) {
init();
}
private static void init() {
SolverFactory<TestSolution> solverFactory = SolverFactory.createFromXmlResource(SOLVER_CONFIG);
Solver<TestSolution> solver = solverFactory.buildSolver();
TestSolution model = new TestSolution();
List<TestEntity> list = new ArrayList<TestEntity>();
// list.add(new TestEntity(){{setValue(7);}});
// list.add(new TestEntity(){{setValue(1);}});
// list.add(new TestEntity(){{setValue(1);}});
// list.add(new TestEntity(){{setValue(1);}});
for (int i = 0; i < 4; i++) {
list.add(new TestEntity());
}
model.setTestEntities(list);
// Solve the problem
TestSolution solution = solver.solve(model);
// Display the result
System.out.println(solution);
}
}
It gets stuck in a local optima because there is no move that takes 1 from entity and gives it to another entity. With a custom move you can add that.
These kind of moves only apply to numeric value ranges (which are rare, usually value ranges are a list of employees etc), but they should probably exist out of the box (feel free to create a jira for them).
Anyway, another way to get the good solution is to add <exhaustiveSearch/>, that bypassing local search and therefore the local optima. But that doesn't scale well.

Adding message to faceContext is not working in Java EE7 run on glassFish?

I am doing the tutorial on Java EE7 that comes with glassFish installation. It is also available here. The code is present in glassFish server installation directory
/glassFish_installation/glassfish4/docs/javaee-tutorial/examples/cdi/guessnumber-cdi.
The code works fine as it is. It currently displays correct! when a user correctly guesses the number but does not display failed at end of the game. so I introduced, just one minor change to display the failed message. I have added comments right above the relevant change in code.
Somehow, this change did not help. That is, the at the end of the game, failed message is not displayed.
But the game works as usual. I would like to know why this did not work and how to correct it?
Thanks
public class UserNumberBean implements Serializable {
private static final long serialVersionUID = -7698506329160109476L;
private int number;
private Integer userNumber;
private int minimum;
private int remainingGuesses;
#Inject
#MaxNumber
private int maxNumber;
private int maximum;
#Inject
#Random
Instance<Integer> randomInt;
public UserNumberBean() {
}
public int getNumber() {
return number;
}
public void setUserNumber(Integer user_number) {
userNumber = user_number;
}
public Integer getUserNumber() {
return userNumber;
}
public int getMaximum() {
return (this.maximum);
}
public void setMaximum(int maximum) {
this.maximum = maximum;
}
public int getMinimum() {
return (this.minimum);
}
public void setMinimum(int minimum) {
this.minimum = minimum;
}
public int getRemainingGuesses() {
return remainingGuesses;
}
public String check() throws InterruptedException {
if (userNumber > number) {
maximum = userNumber - 1;
}
if (userNumber < number) {
minimum = userNumber + 1;
}
if (userNumber == number) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Correct!"));
}
//if remainingGuesses is less than or equal to zero, display failed message
//-----------------------------------------------
if (remainingGuesses-- <= 0) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("failed "));
}
return null;
}
#PostConstruct
public void reset() {
this.minimum = 0;
this.userNumber = 0;
this.remainingGuesses = 10;
this.maximum = maxNumber;
this.number = randomInt.get();
}
public void validateNumberRange(FacesContext context,
UIComponent toValidate,
Object value) {
int input = (Integer) value;
if (input < minimum || input > maximum) {
((UIInput) toValidate).setValid(false);
FacesMessage message = new FacesMessage("Invalid guess");
context.addMessage(toValidate.getClientId(context), message);
}
}
}
Adding the FacesMessage is actually working, the problem is that you are using postdecrement in your condition.
Postdecrement, as the name suggests, is decremented AFTER the execution of the statement containing the postdecrement.
That means, if you write:
if (remainingGuesses-- <= 0) {
the var remainingGuesses is decremented after the if-condition was evaluated.
In your case, when the last guess is checked, remainingGuesses is actually 1 and therefore the if-condition is not true and the message is not added.
Different obvious solutions:
if (remainingGuesses-- <= 1) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("failed "));
}
or
if (--remainingGuesses <= 0) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("failed "));
}
or
remainingGuesses--;
if (remainingGuesses <= 0) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("failed "));
}
See also:
Is there a difference between x++ and ++x in java?
Difference between i++ and ++i in a loop?

JPA named query match a list of tuples in IN clause

spring data jpa 1.4.3 with Oracle 11g.
I have an entity like this:
class LinkRecord {
String value;
int linkType;
...
}
I am using (value, linkType) as a composite index.
For a given list of (v, t) tuples, we need to select all the records in the DB so that value = v, linkType = t.
Basically, I want to build this query:
SELECT * FROM LINK_RECORD WHERE (VALUE, LINK_TYPE) IN (('value1', 0), ('value2', 25), ...)
where the list in the IN clause is passed in as a param.
Since we're working with a large volume of data, it would be very undesirable to query for the tuples one by one.
In my repository I've tried this:
#Query("select r from LinkRecord r where (r.value, r.linkType) in :keys")
List<LinkRecord> findByValueAndType(#Param("keys")List<List<Object>> keys);
where keys is a list of (lists of length 2). This gets me ORA_00920: invalid relational operator.
Is there any way to make this work using a named query? Or do I have to resort to native sql?
The answer is too late, but maybe some1 else has the same problem. This is one of my working examples. Here I need to search for all entries that match a given composite key:
The entity....
#Entity
#NamedQueries({
#NamedQuery(name = "Article.findByIdAndAccessId", query = "SELECT a FROM Article a WHERE a.articlePk IN (:articlePks) ORDER BY a.articlePk.article")
})
#Table(name = "ARTICLE")
public class Article implements Serializable
{
private static final long serialVersionUID = 1L;
#EmbeddedId
private ArticlePk articlePk = new ArticlePk();
#Column(name = "art_amount")
private Float amount;
#Column(name = "art_unit")
private String unit;
public Article()
{
}
//more code
}
The PK class....
#Embeddable
public class ArticlePk implements Serializable
{
private static final long serialVersionUID = 1L;
#Column(name = "art_article")
private String article;
#Column(name = "art_acc_identifier")
private Long identifier;
public ArticlePk()
{
}
public ArticlePk(String article, Long identifier)
{
this.article = article;
this.identifier = identifier;
}
#Override
public boolean equals(Object other)
{
if (this == other)
{
return true;
}
if (!(other instanceof ArticlePk))
{
return false;
}
ArticlePk castOther = (ArticlePk)other;
return this.article.equals(castOther.article) && this.identifier.equals(castOther.identifier);
}
#Override
public int hashCode()
{
final int prime = 31;
int hash = 17;
hash = hash * prime + this.article.hashCode();
hash = hash * prime + this.identifier.hashCode();
return hash;
}
//more code
}
Invocation by....
TypedQuery<Article> queryArticle = entityManager.createNamedQuery("Article.findByIdAndAccessId", Article.class);
queryArticle.setParameter("articlePks", articlePks);
List<Article> articles = queryArticle.getResultList();
where....
articlePks is List<ArticlePk>.

Iterate on a range of iterable

I have interface that returns a iterable object.
I need to iterate on the first 1000 items of it.
What is the best way to combine iterating using Iterator and stop after a certain count is reached.
Thanks
I'd use a loop that iterates and have a counter variable incremented; then break out of the loop when the counter reaches 1000.
What is your language?
C#:
using System.Linq;
//...
foreach (var item in iface.GetIterable().Take(1000))
{
//...
}
Python:
import itertools
#...
for item in itertools.islice(iface.get_iterable(), 1000):
#...
Make a standard loop that iterates over your collection, but check to see if the index has progress past the target index.
You may want to extract a seperate counter from the main loop index for your specific application.
int stopIndex = 1000;
for (int index = 0; index <= theInterface.Count; index++)
{
// check to see if we're at/past the stopIndex
if (index >= stopIndex)
break;
// we're still within the conditions, so do something with your interface
myObjectType localObject = (MyObjectType)theInterface.IndexOf(index);
}
Here's a test-driven (Java) wrapper around any existing iterator that should do the trick.
package com.playground;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import junit.framework.TestCase;
public class LimitedIterableTest extends TestCase {
private static class LimitedIterator<T> implements Iterator<T> {
private final Iterator<T> original;
private final int limit;
private int index = 0;
public LimitedIterator(Iterator<T> iterator, int limit) {
this.original = iterator;
this.limit = limit;
}
public boolean hasNext() {
return index < limit && original.hasNext();
}
public T next() {
index++;
return original.next();
}
public void remove() {
original.remove();
}
}
private static class LimitedIterable<T> implements Iterable<T> {
private final int limit;
private final Iterable<T> original;
public LimitedIterable(Iterable<T> iterable, int limit) {
this.original = iterable;
this.limit = limit;
}
public Iterator<T> iterator() {
return new LimitedIterator<T>(original.iterator(), limit);
}
}
final Integer[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
final List<Integer> list = Arrays.asList(array);
public void testCount() throws Exception {
assertEquals(10, count(list));
}
public void testLimitedIterable() throws Exception {
Iterable<Integer> limited = new LimitedIterable<Integer>(list, 5);
assertEquals(5, count(limited));
limited = new LimitedIterable<Integer>(list, 50);
assertEquals(10, count(limited));
}
private static <T> int count(Iterable<T> iterable) {
Iterator<T> iterator = iterable.iterator();
return count(iterator);
}
private static <T> int count(Iterator<T> iterator) {
int count = 0;
while (iterator.hasNext()) {
iterator.next();
count++;
}
return count;
}
}