How to Sort an Array by Similarity in Relation to an Inputted Word

How to sort an array of string by similarity to specific key

You can define your own similarity sorting method. Note that I have also added a hasPrefix priority over the ones which only contains the keyword which you can just remove if you don't want it:

var theArray = ["chill", "nifty", "precooled", "cooldaddy", "cool", "coolguy", "dandy", "uncool"]
let key = "cool"

let sorted = theArray.sorted {
if $0 == key && $1 != key {
return true
}
else if $0.hasPrefix(key) && !$1.hasPrefix(key) {
return true
}
else if !$0.hasPrefix(key) && $1.hasPrefix(key) {
return false
}
else if $0.hasPrefix(key) && $1.hasPrefix(key)
&& $0.count < $1.count {
return true
}
else if $0.contains(key) && !$1.contains(key) {
return true
}
else if !$0.contains(key) && $1.contains(key) {
return false
}
else if $0.contains(key) && $1.contains(key)
&& $0.count < $1.count {
return true
}
return false
}

print(sorted) // ["cool", "coolguy", "cooldaddy", "uncool", "precooled", "chill", "nifty", "dandy"]

You can also extend Sequence and create a sorted by key similarity method:

extension Sequence where Element: StringProtocol {
func sorted<S>(by key: S) -> [Element] where S: StringProtocol {
sorted {
if $0 == key && $1 != key {
return true
}
else if $0.hasPrefix(key) && !$1.hasPrefix(key) {
return true
}
else if !$0.hasPrefix(key) && $1.hasPrefix(key) {
return false
}
else if $0.hasPrefix(key) && $1.hasPrefix(key)
&& $0.count < $1.count {
return true
}
else if $0.contains(key) && !$1.contains(key) {
return true
}
else if !$0.contains(key) && $1.contains(key) {
return false
}
else if $0.contains(key) && $1.contains(key)
&& $0.count < $1.count {
return true
}
return false
}
}
}


let sorted = theArray.sorted(by: key)  // "cool", "coolguy", "cooldaddy", "uncool", "precooled", "chill", "nifty", "dandy"]

And the mutating version as well:

extension MutableCollection where Element: StringProtocol, Self: RandomAccessCollection {
mutating func sort<S>(by key: S) where S: StringProtocol {
sort {
if $0 == key && $1 != key {
return true
}
else if $0.hasPrefix(key) && !$1.hasPrefix(key) {
return true
}
else if !$0.hasPrefix(key) && $1.hasPrefix(key) {
return false
}
else if $0.hasPrefix(key) && $1.hasPrefix(key)
&& $0.count < $1.count {
return true
}
else if $0.contains(key) && !$1.contains(key) {
return true
}
else if !$0.contains(key) && $1.contains(key) {
return false
}
else if $0.contains(key) && $1.contains(key)
&& $0.count < $1.count {
return true
}
return false
}
}
}


order an array based on input - php

I've done some research, here is a way that you could do it:

$array = array(0 => 'blue', 1 => 'reds', 2 => 'green', 3 => 'reds'); 
//Words to be searched from.

$res = array("percent" => "0", "word" => "N/A");
//Result, this is an array for the bellow loop to talk to.

foreach($array AS $ar){
similar_text("red", $ar, $percent);

//If it's more like the word, then replace the percentage with the percentage of similarity & word.
if($percent > $res["percent"]){
$res["percent"] = $percent;
$res["word"] = $ar;
}
}

//Echo out the most similar word.
echo $res["word"];

From what I could find, this was the only way possible for doing something like this.

PHP: Sort Multidimensional Array Based on Term in relation to a value of a key

Here's a function that I think will do what you want. I've presumed you want to find the value of $term at the beginning of a word. This code extracts any keyword in the title which includes $term and then sorts based on whether the keyword was found, followed by the ordering of the keyword, or if they are both the same, on the title.

$term = 'geo';
usort($data, function ($a, $b) use ($term) {
// find the term in first entry
$t1 = preg_match("/^.*?\b($term\w*)\b.*\$/i", $a['result_title'], $matches) ? $matches[1] : '';
// find the term in second entry
$t2 = preg_match("/^.*?\b($term\w*)\b.*\$/i", $b['result_title'], $matches) ? $matches[1] : '';
// check if the terms were found
if ($t1 == '' && $t2 != '') return 1;
if ($t1 != '' && $t2 == '') return -1;
// found in both - if not the same, just sort on the keyword
if ($t1 != $t2) return strcmp($t1, $t2);
// found the same keyword, sort on the whole title
return strcmp($a['result_title'], $b['result_title']);
});

Since the output is long (it is what you asked for) I've omitted it but I've made a demo on 3v4l.org.

sort php array by relevance

You could use usort with a callback function that utilizes levenshtein() to sort your array.

Sort an array alphabetically based on a search input

An alternative is to check is the strings start with the entered value, and make a decision about the order.

  • When a and b starts with the entered value make a string comparison.
  • If a starts with the entered value and b doesn't then place a at the beginning.
  • If b starts with the entered value and a doesn't then place b at the beginning.
  • Otherwise, make the default string comparison.

var array = [{id: "157", tag: "Adambb", course: "Adambb - Calculus I"}, {id: "158", tag: "Andrebw", course: "Andrebw - Ca I"}, {id: "159", tag: "Bob", course: "Bob - Cass I"}, {id: "160", tag: "Billy", course: "Billy - uus I"}, {id: "161", tag: "Sandrab", course: "Sandrab - allus I"}, {id: "162", tag: "Xaviercb", course: "Xaviercb - Cal I"}];
var input = 'Sa'; // Changed to illustrate the behavior.
var sorted = array.sort((a, b) => { if (a.course.startsWith(input) && b.course.startsWith(input)) return a.course.localeCompare(b.course); else if (a.course.startsWith(input)) return -1; else if (b.course.startsWith(input)) return 1; return a.course.localeCompare(b.course);;});
console.log(sorted);
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to sort array of strings in ascending order in C

This is not an answer, but some criticism of the code you refer to:

#include<stdio.h>
#include<string.h>
int main(){
int i,j,count;
char str[25][25],temp[25];
puts("How many strings u are going to enter?: ");
scanf("%d",&count); // (1)

puts("Enter Strings one by one: ");
for(i=0;i<=count;i++) // (2)
gets(str[i]);
for(i=0;i<=count;i++)
for(j=i+1;j<=count;j++){
if(strcmp(str[i],str[j])>0){
strcpy(temp,str[i]);
strcpy(str[i],str[j]);
strcpy(str[j],temp);
}
}
printf("Order of Sorted Strings:"); // (3)
for(i=0;i<=count;i++)
puts(str[i]);

return 0;
}

And the criticism:

(1) scanf("%d",&count); reads a number into count, and returns after that. It does not consume the line break(!)

(2) this loop does not print anything, just reads. However if you put

  for(i=0;i<=count;i++){
printf("%d:",i);
gets(str[i]);
}

in its place, you will suddenly see that it asks for names 0...5, just skips the 0 automatically. That is where the line break is consumed, it reads an empty string. You can also make it appear, if instead of putting 5 into the initial question, you put 5 anmoloo7.

(3) in the printout the names appear below the title Order of Sorted Strings. But there is no linebreak in that printf. The thing is that the empty string is "smaller" than any other string, so it gets to the front of the list, and that is printed there first. If you do the 'trick' of appending a name after the initial number, the output will look different, there will be 6 names, and one of them appended directly to the title.

Plus there is the thing what you probably get from your compiler too: gets is a deadly function, forget its existence and use fgets with stdin as appears in other answers.

Getting input from text file and storing into array but text file contains more than 20.000 strings

You requirement is to NOT use any standard container like for example a std::vector or a std::unordered_map.

In this case we need to create a dynamic container by ourself. That is not complicated. And we can use this even for storing strings. So, I will even not use std::string in my example.

I created some demo for you with ~700 lines of code.

We will first define the term "capacity". This is the number of elements that could be stored in the container. It is the currently available space. It has nothing to do, how many elements are really stored in the container.

But there is one and the most important functionality of a dynamic container. It must be able to grow. And this is always necessary, if we want to store add more elements to the container, as its capacity.

So, if we want to add an additional element at the end of the container, and if the number of elements is >= its capacity, then we need to reallocate bigger memory and then copy all the old elements to the new memory space. For such events, we will usually double the capacity. This should prevent frequent reallocations and copying activities.

Let me show you one example for a push_back function, which could be implemented like this:

template <typename T>
void DynamicArray<T>::push_back(const T& d) { // Add a new element at the end
if (numberOfElements >= capacity) { // Check, if capacity of this dynamic array is big enough
capacity *= 2; // Obviously not, we will double the capacity
T* temp = new T[capacity]; // Allocate new and more memory
for (unsigned int k = 0; k < numberOfElements; ++k)
temp[k] = data[k]; // Copy data from old memory to new memory
delete[] data; // Release old memory
data = temp; // And assign newly allocated memory to old pointer
}
data[numberOfElements++] = d; // And finally, store the given data at the end of the container
}

This is a basic approach. I use templates in order to be able to store any type in the dynamic array.

You could get rid of the templates, by deleting all template stuff and replacing "T" with your intended data type.

But, I would not do that. See, how easy we can create a "String" class. We just typedef a dynamic array for chars as "String".

using String = DynamicArray<char>;

will give us basic string functionality. And if we want to have a dynamic array of strings later, we can write:

using StringArray = DynamicArray<String>;

and this gives us a DynamicArray<DynamicArray<char>>. Cool.

For this special classes we can overwrite some operators, which will make the handling and our life even more simple.

Please look in the provided code


And, to be able to use the container in the typical C++ environment, we can add full iterator capability. That makes life even more simple.

This needs really some typing effort, but is not complicated. And, it will make life really simpler.


You also wanted to create a hash map. For counting words.

For that we will create a key/value pair. The key is the String that we defined above and the value will be the frequency counter.

We implement a hash function which should be carefully selected to work with strings, has a high entropy and give good results for the bucket size of the hash map.

The hash map itself is a dynamic container. We will also add iterator functionality to it.


For all this I drafted some 700 lines of code for you. You can take this as an example for your further studies.

It can also be easily enhanced with additional functionality.

But caveat: I did only some basic tests and I even used raw pointers for owned memory. This can be done in a schoolproject to learn some dynamic memory management, but not in reality.

Additionlly. You can replace all this code, by simply using std::string, std::vector and std::unordered_map. Nobody would use such code and reinvent the wheel.

But it may give you some ideas on how to implement similar things.

Because Stackoverlof limits the answer size to 32000 characters, I will put the main part on github.

Please click here.

I will just show you main so that you can see how easy the solution can be used:

int main() {

// Open file and check, if it could be opened
std::ifstream ifs{ "r:\\test.txt" };
if (ifs) {

// Define a dynamic array for strings
StringArray stringArray{};

// Use overwritten extraction operator and read all strings from the file to the dynamic array
ifs >> stringArray;

// Create a dynamic hash map
HashMap hm{};

// Now count the frequency of words
for (const String& s : stringArray)
hm[s]++;

// Put the resulting key/value pairs into a dynamic array
DynamicArray<Item> items(hm.begin(), hm.end());

// Sort in descending order by the frequency
std::sort(items.begin(), items.end(), [](const Item& i1, const Item& i2) { return i1.count > i2.count; });

// SHow resulton screen
for (const auto& [string, count] : items)
std::cout << std::left << std::setw(20) << string << '\t' << count << '\n';
}
else std::cerr << "\n\nError: Could not open source file\n\n";
}


Related Topics



Leave a reply



Submit