sort array by first item in subarray c++
One way to sort the array is to not sort the array itself.
Instead, sort an array of indices that point inside of the array, and then use the sorted index to access the elements. It is much easier to do that than to manipulate a 2d array in a sorting function.
In general, if you have the memory for the array of indices (we will need additional storage for the index array), sorting objects that have
- a large payload per item, or
- the original order of the array needs to be kept around, or
- sorting is just clumsy1 or impossible to manipulate easily in a sorting algorithm,
can use this technique that will be described here.
Here is an example:
#include <algorithm>
#include <iostream>
int main()
{
int index[3] = {0,1,2};
int timeTable[3][2] = {{4, 204}, {10, 39}, {1, 500}};
std::sort(index, index + 3, [&](int n1, int n2){ return timeTable[n1][0] < timeTable[n2][0]; });
for (int i = 0; i < 3; ++i)
std::cout << "The index is " << index[i] << ". The data at this index is [" <<
timeTable[index[i]][0] << " " << timeTable[index[i]][1] << "]\n";
}
Live Example
So basically we create an initial index array numbered from 0 to n-1
where n
are the number of items to sort. Then we call std::sort
on the index, and in the sorting criteria, we compare the items in the actual array using the indices passed to the sorting predicate. The result will be the index array having its elements swapped around during the sort instead of the original array's elements being swapped.
Note that the sorting predicate is very simple -- we state exactly what we want the indices to represent in the sort by using the indices being passed on the timeTable
array. There is no tricky, error-prone, or code that does not scale well if one of the items is out of order (for example, the parallel array scenario -- imagine 20 arrays and having to swap 20 items just because one item is out of order).
After sorting the indices, when it comes time to use the timeTable
array, we use the index array to point to the items (note how we specify the index by using timeTable[index[i]][0]
instead of timeTable[i][0]
).
1 Included in the "clumsy" category are those "parallel
array sort" questions that show up on StackOverflow, where the poster is asked to sort multiple arrays "in parallel" based on data in one of those arrays.
Sort 2d C++ array by first element in subarray
Use a std::vector
of std::vector
as your container and the sort becomes much easier to do with. Not only is std::vector
the preferred container for C++ but using STL functions on it is way simpler and direct , without any substantiable overhead.
Define your data as
std::vector<std::vector<int>> umbrellas{
{5, 6},
{2, 7},
{9, 20}
};
Now you can use a custom comparator lambda that takes in two vector element references and returns True when the first element of the above vector is smaller than that of the one below.
std::sort(umbrellas.begin(),
umbrellas.end(),
[](const std::vector<int> &above, const std::vector<int> &below)
{
return (above[0] < below[0]);
});
And the output :
for (auto &&row : umbrellas) {
for (auto element : row) {
std::cout<< element<< " ";
}
std::cout<< "\n";
}
2 7
5 6
9 20
Taking this to C++20 it's even easier:
std::ranges::sort(umbrellas, std::less(),
[](const auto &v) { return v[0];});
Sort subarrays according to their first element
Assuming Grid
implements Comparable<Grid>
, sort each array and add to 2d-array. Then sort that array of arrays of grids using Arrays.sort(Grid[][], GridArrayComparator)
, where GridArrayComparator
looks for example like:
class GridArrayComparator implements Comparator<Grid[]> {
public int compare(Grid[] grids1, Grid[] grids2) {
if (grids1.length > 0 && grids1.length > 0) {
return grids1[0].compareTo(grids2[0]);
} else if (grids1.length > 0) {
return 1;
} else if (grids2.length > 0) {
return -1;
} else {
return 0;
}
}
}
Then copy 2-d array to 1-d array.
Alphabetically sort array by sub-array's first element
<?php
$array = array(
0 => array('a', '1', '2', '3', '4', 'test'),
1 => array('c', '1', '2', '3', '5', 'test'),
2 => array('b', '1', '3', '4', '5', 'test'),
);
array_multisort(array_column($array, 1), SORT_ASC, $array);
print_r($array);
Output:
Array
(
[0] => Array
(
[0] => a
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => test
)
[1] => Array
(
[0] => b
[1] => 1
[2] => 3
[3] => 4
[4] => 5
[5] => test
)
[2] => Array
(
[0] => c
[1] => 1
[2] => 2
[3] => 3
[4] => 5
[5] => test
)
)
https://eval.in/633355
Sorting Subarrays in C Sorts Entire Array Instead?
I compiled your sort_cards()
function (after providing the missing }
), with GCC 7.2.0 on a Mac and the command line:
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
-Wstrict-prototypes -c cards53.c
With these options (the critical one is -Wextra
), it warns immediately:
cards53.c:31:34: error: comparison of unsigned expression >= 0 is always true [-Werror=type-limits]
for (size_t j = i - 1; j >= 0; j--)
That indicates a serious problem. Especially as on the first iteration of the outer loop, i
is 0
, so i - 1
is a very big number. Frankly, your claim that the function will sort an entire array successfully is bogus. It won't. And I don't run code that won't compile with the command line shown.
If you fix that function, your code is then OK. I used:
#include <stdio.h>
#define n_H 10
#define n_C 104
static inline void card_swap(char *deck, int i1, int i2)
{
char t = deck[i1];
deck[i1] = deck[i2];
deck[i2] = t;
}
static void sort_cards(char *cards, size_t n)
{
for (size_t i = 1; i < n; i++)
{
for (size_t j = i; j-- > 0; )
{
if (cards[j] > cards[j + 1])
card_swap(cards, j, j + 1);
else
break;
}
}
}
static void sort_hands(char *deck, size_t n_P)
{
for (size_t i_P = 0; i_P < n_P; i_P++)
sort_cards(deck + i_P * n_H, n_H);
}
static void dump_hands(const char *tag, const char *deck, size_t n_P)
{
printf("%s:\n", tag);
for (size_t p = 0; p < n_P; p++)
{
printf("Player %zu:", p + 1);
const char *hand = deck + p * n_H;
for (int i = 0; i < n_H; i++)
printf(" %3d", hand[i]);
putchar('\n');
}
}
int main(void)
{
char deck[n_C] =
{
74, 31, 53, 46, 42, 75, 72, 77, 70, 49,
76, 86, 99, 78, 11, 94, 61, 14, 41, 87,
40, 26, 92, 5, 9, 3, 66, 63, 101, 98,
};
int n_P = 3;
dump_hands("Before", deck, n_P);
sort_hands(deck, n_P);
dump_hands("After", deck, n_P);
return 0;
}
The array is initialized with the sample data you gave; the residue is all zeros, but that doesn't matter for this exercise.
Sample output:
Before:
Player 1: 74 31 53 46 42 75 72 77 70 49
Player 2: 76 86 99 78 11 94 61 14 41 87
Player 3: 40 26 92 5 9 3 66 63 101 98
After:
Player 1: 31 42 46 49 53 70 72 74 75 77
Player 2: 11 14 41 61 76 78 86 87 94 99
Player 3: 3 5 9 26 40 63 66 92 98 101
Inspection shows that the each sub-array is correctly sorted.
Sorting an array using subscripts without moving array elements
Ok. lets start with a simple example, a list of 4 elements to sort, lets go through the process of what your function needs to do and how it does it in terms of linked lists:
#->[3]->[1]->[4]->[2]->$
Ok, so here # is your pointer to the first element, in this case [3]
, which has a pointer to the second, and so on. I shall use ->$
as a null pointer (not pointing to anything) and ->*
as a 'I don't care' pointer (where a pointer may exist, but want to show a conceptional break in the list)
We now perform multiple passes to merge these into one sorted list.
This is the first pass, so we treat it as if we have multiple lists of length 1
:
#->* [3]->* [1]->* [4]->* [2]->*
In reality, these remain linked for now, but this is the conceptional model.
so what to we need 'know' at this time?
- the end of the list before list #1
- reference to beginning of list #1
- reference to beginning of list #2
- reference to item after list #2
Then we merge the two sublists (2) and (3) onto the end of (1), by taking the minimum of the heads of the lists, detaching that, and ammending it to (1), moving onto the next value in that list if it exists
conceptional
//sublists length 1. we'll work on the first pair
#->* [3]->* [1]->* [4]->* [2]->*
//smallest element from sublists added to new sublist
#->* [3]->* [4]->* [2]->* //
[1]->*
//above repeated until sublists are both exhausted
#->* [4]->* [2]->*
[1]->[3]->*
//we now have a sorted sublist
#->* [1]->[3]->* [4]->* [2]->*
actual
//(1-4) are pointers to the list as per description above
#->[3]->[1]->[4]->[2]->$
| | | |
1 2 3 4
//set the end of the lists (2) and (3) to point to null, so
//when we reach this we know we have reached the end of the
//sublist (integrity remains because of pointers (1-4)
#->* [3]->$ [1]->$ [4]->[2]->$
| | | |
1 2 3 4
//the smallest (not null) of (2) and (3) is referenced by (1),
//update both pointers (1) and (2) or (3) to point to the next
//item
#->[1]->* [3]->$ $ [4]->[2]->$
| | | |
1 2 3 4
//repeat until both (2) and (3) point to null
#->[1]->[3]->* $ $ [4]->[2]->$
| | | |
1 2 3 4
We now have a linked list with the first sublist in it. Now, we keep track of (1), and move on to the second pair of sublists, starting with (4), repeating the process.
Once (2),(3) and (4) are all null, we have completed the pass. We now have sorted sublists, and a single linked list again:
#->[1]->[3]->[2]->[4]->$ $ $ $
| | | |
1 2 3 4
Now we do the same, only with sublists twice the length. (and repeat)
The list is sorted when sublist length >= length of linked list.
At no point during this have we actually moved any data around, only modified the links between the items in the linked list.
This should give you a solid idea of what you need to do from here.
I've extended this to some actual code:
See it here
I wrote it in python, so it satisfies your desire for pseudocode, as it isn't code for the language that you are writing in.
pertinent function with additional comments:
def mergesort(unsorted):
#dummy start node, python doesn't have pointers, but we can use the reference in here in the same way
start = llist(None)
start.append(unsorted)
list_length = unsorted.length()
sublist_length = 1
#when there are no sublists left, we are sorted
while sublist_length < list_length:
last = start
sub_a = start.next
#while there are unsorted sublists left to merge
while sub_a:
#these cuts produce our sublists (sub_a and sub_b) of the correct length
#end is the unsorted content
sub_b = sub_a.cut(sublist_length)
end = sub_b.cut(sublist_length) if sub_b else None
#I've written this so is there are any values to merge, there will be at least one in sub_a
#This means I only need to check sub_a
while sub_a:
#sort the sublists based on the value of their first item
sub_a, sub_b = sub_a.order(sub_b)
#cut off the smallest value to add to the 'sorted' linked list
node = sub_a
sub_a = sub_a.cut(1)
last = last.append(node)
#because we cut the first item out of sub_a, it might be empty, so swap the references if so
#this ensures that sub_a is populated if we want to continue
if not sub_a:
sub_a, sub_b = sub_b, None
#set up the next iteration, pointing at the unsorted sublists remaining
sub_a = end
#double the siblist size for the next pass
sublist_length *=2
return start.next
How to store the original indices of array after sorting the array in ascending ordering
The issue is that you are sorting the original array_dist
when you shouldn't be sorting this at all.
You should only sort the index_array
based on the comparison of the array_dist
values :
// Compare values at `array_dist`, using the index array
if (array_dist[index_array[i]] > array_dist[index_array[j]])
{
// the indices need to be swapped
x = index_arr[i];
index_arr[i] = index_arr[j];
index_arr[j] = x;
}
Once you have this, then to print out the array_dist
in sorted order:
for (int i = 0; i < 4344; ++i)
{
cout << index_arr[i] << " : "
<< array_dist[index_arr[i]] << endl;
}
You use the index_array
as a subscript within the original array.
Related Topics
Force to Link Against Unused Shared Library
Realloc Without Freeing Old Memory
How to Correctly Interpose Malloc Allowing for Ld_Preload Chaining
How to Write Log Base(2) in C/C++
Iterating Over a Struct in C++
Correct Use of Std::Cout.Precision() - Not Printing Trailing Zeros
In Which Order Should Floats Be Added to Get the Most Precise Result
Does There Exist a Static_Warning
Destroy and Then Construct New Object Using the Same Variable
How to Monitor a Folder with All Subfolders and Files Inside
Segmentation Fault When Sending Struct Having Std::Vector Member
What Is the Easiest Way to Parse an Ini File in C++
Read Unicode Utf-8 File into Wstring
Regex Replace with Callback in C++11