简体   繁体   中英

How to create a new array from two and initialize the new one based on values in original arrays

I'm new to Java, and I'm not sure how to ask the right question, so please bear with me. I have 40 total items of 6 different types to put into a new array; each item type has a different cost. The first item (quantity=1) costs $3, the second item (qty=2) costs $5 each, the third item (qty=4) costs $9 each, and so on. The quantity of each item type is in numTypeIndArray and the cost for each type is in costCSDriverArray . A cumulative count of the total items is in numTypeCumulArray .

So, the new array, indItemCostArray , should be single dimensional and have 40 elements. It would look something like {3,5,5,9,9,9,9,...,13,13,13} , but the last fifteen elements are a cost of $13. How do I get to this array with 40 elements? I started with trying to fill the array using a nested for loop but I haven't gotten there yet. The code below is plain wrong.

int[] costArray = new int[]{3,5,9,10,11,13};
int[] numTypeIndArray = new int[]{1,2,4,7,11,15};
int[] numTypeCumulArray = new int[]{1,3,7,14,25,40};

int[] indItemCostArray = new int[numTypeCumulArray[6]];

for (int i = 0; i < indItemCostArray.length; i++) {
    for (int j = 0; j < numTypeIndArray[i]; j++) {
        indItemCostArray[i+j] = costArray[j];
    }
}

First of all, you'll get a ArrayOutOfBoundException at:

int[] indItemCostArray = new int[numTypeCumulArray[6]];

The size of the array numTypeCumulArray is 6, and arrays are 0 indexed. So, The last index number is 5, not 6, as indexing started from 0.

You can do as follows for accessing the last element of the array:

int[] indItemCostArray = new int[numTypeCumulArray[numTypeCumulArray.length - 1]];

Secondly, you're running your outer loop for 40 times and for each iteration your inner loop is trying to iterate for numTypeIndArray[i] times, where i is the iterator variable of outer loop. So, surely after sixth iteration, when value of i will be 6 , your program will again throw the ArrayOutOfBoundException as you're accessing a value in the terminator condition of the inner loop from numTypeIndArray whose last index is 5.

Again, inside the inner loop, you're assigning indItemCostArray at index position i+j , which will actually far from your purpose.

To achieve what you are exactly expecting, you can do as follows:

int currentIndex =0;

for (int costIndex = 0; costIndex < costArray.length; costIndex++) {
    for(int index = currentIndex;  index < currentIndex + numTypeIndArray[costIndex]; index++) {
        indItemCostArray[index] = costArray[costIndex];
    }
    currentIndex = numTypeCumulArray[costIndex];
}

Here, what I did is, in the outer loop I iterated the same amount of time the length of costArray , you can take the length of numTypeIndArray instead too, no issue. I've defined a variable named currentIndex to keep track of the current assignable index for array indItemCostArray . In the inner loop, I tried to begin with the currentIndex and loop upto the time same as the number of items needed for that type, given in numTypeIndArray[costIndex] , and for each iteration, set the corresponding index of indItemCostArray with the cost of costIndex in the costArray . Finally, I update the currentIndex with the corresponding cumulative total items from numTypeCumulArray .

Hope you got everything clear.

The whole setup of three arrays is kind of weird. The weiredest is the third array. Think carefully, do you actually need it? You already have all the information in your second array. The third array can introduce a lot of unnacessary mistakes.

But, assuming that you actually need these arrays for some reason and there are no mistakes in making these arrays. You can get your required fourth array as follows,

int[] costArray = new int[]{3,5,9,10,11,13};
int[] numTypeIndArray = new int[]{1,2,4,7,11,15};
int[] numTypeCumulArray = new int[]{1,3,7,14,25,40};

// you want to make sure that your arrays are of same lenght
assert(costArray.length == numTypeIndArray.length && costArray.length == numTypeCumulArray.length);

// length of these arrays is unique items count
int uniqueItemsCount = costArray.length;

// totalItemsCount is last element of numTypeCumulArray
int totalItemsCount = numTypeCumulArray[uniqueItemsCount - 1];

int[] indItemCostArray = new int[totalItemsCount];

// use this to keep track of index in indItemCostArray
int itemCostIndex = 0;

for (int i = 0; i < uniqueItemsCount && itemCostIndex < totalItemsCount; i++) {
    for (int j = 0; j < numTypeIndArray[i] && itemCostIndex < totalItemsCount; j++) {
        indItemCostArray[itemCostIndex] = costArray[j];
        // increase the index for next item cost
        itemCostIndex += 1;
    }
}
    int[] costArray = new int[]{3,5,9,10,11,13};
    int[] numTypeIndArray = new int[]{1,2,4,7,11,15};
    int[] numTypeCumulArray = new int[]{1,3,7,14,25,40};

    int[] indItemCostArray = new int[numTypeCumulArray[5]];

    int num = 0;
    for (int i = 0; i < numTypeIndArray.length; i++) {
        for (int j = 0; j < numTypeIndArray[i]; j++) {
            indItemCostArray[num + j] = costArray[i];
        }
        num += numTypeIndArray[i];
    }

    System.out.println(Arrays.toString(indItemCostArray));

First, you don't need int[] numTypeCumulArray = new int[]{1,3,7,14,25,40};

It just shows the cumulative values of the numTypeIndArray . The last value, 40 is just the sum of numTypeIndArray and that would be the size of the resulting array from your requirement.

It can be summed in a simple for loop or you can do it like this and then create the target array.

int maxSize = Arrays.stream(numTypeIndArray).sum();
int[] indItemCostArray = new int[maxSize];

Then you could proceed to populate the array with the values as has been shown. Here is another way using streams which you will undoubtedly learn about. The quick explanation is that it creates multiple streams of the proper quantities of cost.

e.g
stream1 -> {3}
stream2 -> {5,5};
stream3 -> {9,9,9,9} etc.

Then it flattens them in a single stream of those values and returns an array.

int[] result = IntStream.range(0, costArray.length)
        .flatMap(i -> IntStream.range(0, numTypeIndArray[i])
                .map(q -> costArray[i]))
        .toArray();

But using a class to hold the information would be better. Here is one example.

class Product {
    private String name;
    private int cost;
    private int quantity;
    public Product(String name, int cost, int quantity) {
        this.name = name;
        this.cost = cost;
        this.quantity = quantity;
    }
    public int getCost() {
        return cost;
    }
    public int getQuantity() {
        return quantity;
    }
    public String getName() {
        return name;
    }
    
    @Override 
    public String toString() {
        return new StringJoiner(", ","[", "]").add(name).add("cost="+cost).add("quantity="+quantity).toString();
    }
}

And it can be used like so.

List<Product> products = new ArrayList<>();
for (int i = 0; i < costArray.length; i++) {
        products.add(new Product("Item" + (i+1), costArray[i], numTypeIndArray[i]));
}
products.forEach(System.out::println);

Prints

[Item1, cost=3, quantity=1]
[Item2, cost=5, quantity=2]
[Item3, cost=9, quantity=4]
[Item4, cost=10, quantity=7]
[Item5, cost=11, quantity=11]
[Item6, cost=13, quantity=15]

And once again it can be streamed to create your results exactly as before only using the class getters to get the values.

        
int[] result2 = products.stream()
        .flatMapToInt(
                prod -> IntStream.range(0, prod.getQuantity())
                        .map(q -> prod.getCost()))
        .toArray();

The two arrays result and result2 are identical. But you may find that using classes may eliminate the requirement for creating such an array.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM